10 Things I Hate About Scala
About Me
Meir Maor
Chief Architect @ SparkBeyond
At SparkBeyond we leverage the collective human knowledge to solve the world's toughest problems
1. Type Inference Limitations
Pop Quiz: What does the following expression return?
scala> List("foo").toSet.head.head<console>:8: error: value head is not a member of type parameter B List("foo").toSet.head.head ^
List("foo").toSet.head.head
Why?
def toSet[B >: A]: immutable.Set[B] = to[immutable.Set].asInstanceOf[immutable.Set[B]]
The required type should affect type inference: val a: Set[Any] = List("foo").toSet
But not break Set Invariance: val aSet: Set[String] = Set("foo") val b: Set[Any] = aSet
As we want to use [A] in both variant and co-variant positions: val s=Set("foo") List("foo","bar").filter(s)
Type Inference – Cont.
Make up test: math.sqrt(Some(1).getOrElse(1))
<console>:8: error: type mismatch; found : AnyVal required: Double math.sqrt(Some(1).getOrElse(1)) ^
Workarounds
Use to[Set] instead of toSet:
List("foo").to[Set].head.head
Explicitly state type parameter [Int]:
math.sqrt(Some(1).getOrElse[Int](1))
Assign a variable to force a concrete type sooner.
Fixing the root cause
Requires adding Back-tracking after failure(less efficient)
Not planned for upcoming release
2. Type Erasure
List(“foo”) match {case x: List[Int] => 1case x: List[_] => 2
}
Structural Type Erasure
val z: Any = "foo"
z match {
case x: { def noSuchMethod() : Int } => "???"
case _ => "OK"
}
Type Erasure – Why
Odersky did it. (in Java)
Prevents generation of extra classes and overhead.
Refied Types (like reflection) enable breaking type safety
Type Erasure - Workarounds
def foo[T](a: T)(implicit ev: TypeTag[T]) = { ev.tpe <:< typeOf[Seq[String]] }
def foo[T: TypeTag](a: T) = { typeOf[T] <:< typeOf[Seq[String]] }
def putInArray[T: ClassTag](a: T) = { val res = new Array[T](1) res(0) = a res }
More Workarounds
When TypeTags won't do:● Pattern match member of collection
(implies non empty)● Check members reflectively explicitly
(for structural type)● Restructure to keep type safety
Type Erasure - Solutions
Fully Reified types - Not going to Happen
More Sugar may be added around TypeTags while keeping them optional.
3) Binary Incompatibility
● Scala 2.11.x / 2.10.x / 2.9.x aren’t compatible with each other.
● Libraries need to be cross-compiled to different Scala versions.
● Source compatibility isn’t perfect either.
Mitigations
● Cross compiling, upgrade libraries, compile library from source yourself.
● Community builds
● Last resort: Separate JVM
● Isolate ClassLoaders (OSGI)
4. Overloading with default arguments
object Foo { def foo(a: Int, b: String = "foo") def foo(a: Double, b: String = "foo")}
error: in object Foo, multiple overloaded alternatives of method foo define default arguments
Why?
● In order to have a deterministic naming-scheme for the generated methods which return default arguments.
If you write def foo(a: Int,b: String = "foo")
the compiler generates: def foo$default$2 = "foo"
● If two overloads have default parameters,the generated code will conflict.
Workaround
Avoid overloadswhen you need
default parameters :(
Fixing the root problem
● Nothing stopping it.
● Doesn’t seem to be anyone's top priority.
● A possible solution would beadding the disambiguating types to the generated method signature.
5. Standard Library - Performance
Dearth of overriding implementations for performance:
def getOrElseUpdate(key: A, op: => B): B =
get(key) match { case Some(v) => v case None => val d = op; this(key) = d; d }
override def add(elem: Int): Boolean = {
require(elem >= 0)
if (contains(elem)) false
else {
val idx = elem >> LogWL
updateWord(idx, word(idx) | (1L << elem))
true
}
}
6. Standard Library - Quality
Bugs escape:
Range equality - 2.11.0, 2.11.1 (0 until 0) == (0 until 10) // True
(0 until 10) == (0 until 0) // NoSuchElementException
Searching: (Should return Insertion point for missing value)
Vector(1,2,4).search(0) // InsertionPoint(-1)
Why
The Scala standard library is very rich
Efforts focus more on the compiler
Mitigation
Know what's going on inside
Don't assume you can't do better than the standard library.
Solutions
Focus of up-coming versions
Smaller Standard Library
7. Equality type unsafety
if (“foo” == 4) 1 else 2// Compiles no warning
if (4 == “foo”) 1 else 2
// Compiles with warning
Developers can do many things
Proving the scala compiler wrong:
case class Foo(a: Int)
class Foo2(a: Int) extends Foo(a) { // Bad Idea override def equals(other: Any) = true}
val a: Foo = Foo2(1)
a == 1<console>:62: warning: comparing values of types Bar andInt using `==' will always yield false
a == 1
^
res39: Boolean = true
Why?
● Interoperability with Java● Simplicity
Mitigations
Scalaz === operator, gives compile time type safety.scala> 1 === 1
res0: Boolean = true
scala> 1 === "foo"
<console>:14: error: could not find implicit value for parameter F0: scalaz.Equal[Object]
1 === "foo"
^
8. Explicit method return types
There are (too) many cases you must define an explicit method return type:
● Explicitly call return in a method (even at the end)● Recursive methods● A method is overloaded and one of the methods calls
another. The calling method needs a return type annotation.
● The inferred return type would be more general than you intended, e.g. Any
Why
Some cases are difficult to infer
Need simple rules for requiring explicit types
Simple rules are overly broad
9. Compile time
● Scala compilation lines/sec is~10X slower than Java
● More functionality per line can shrink the difference to 3X-5X range (benchmarks vary wildly)
Solution / Mitigations:
● SBT - for incremental compile (new flag)● Supply explicit return types● An area of continuous improvement in Scala
10. REPL Is Different
val a = (1, 2)println(a.getClass)println(a.getClass.getSuperclass)
Compiling and running normally:class scala.Tuple2$mcII$sp ←Specializationclass scala.Tuple2
From Repl:a: (Int, Int) = (1,2)
class scala.Tuple2
class java.lang.Object
Final Thoughts
Scala is definitely production grade
Happily been using in production for 3 years
Undergoing constant improvement
You can take an active part in improving Scala
Thank You
Join Us