Transcript
Page 1: 10 Things I Hate About Scala

10 Things I Hate About Scala

Page 2: 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

Page 3: 10 Things I Hate About Scala

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

Page 4: 10 Things I Hate About Scala

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)

Page 5: 10 Things I Hate About Scala

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)) ^

Page 6: 10 Things I Hate About Scala

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.

Page 7: 10 Things I Hate About Scala

Fixing the root cause

Requires adding Back-tracking after failure(less efficient)

Not planned for upcoming release

Page 8: 10 Things I Hate About Scala

2. Type Erasure

List(“foo”) match {case x: List[Int] => 1case x: List[_] => 2

}

Page 9: 10 Things I Hate About Scala

Structural Type Erasure

val z: Any = "foo"

z match {

case x: { def noSuchMethod() : Int } => "???"

case _ => "OK"

}

Page 10: 10 Things I Hate About Scala

Type Erasure – Why

Odersky did it. (in Java)

Prevents generation of extra classes and overhead.

Refied Types (like reflection) enable breaking type safety

Page 11: 10 Things I Hate About Scala

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 }

Page 12: 10 Things I Hate About Scala

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

Page 13: 10 Things I Hate About Scala

Type Erasure - Solutions

Fully Reified types - Not going to Happen

More Sugar may be added around TypeTags while keeping them optional.

Page 14: 10 Things I Hate About Scala

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.

Page 15: 10 Things I Hate About Scala

Mitigations

● Cross compiling, upgrade libraries, compile library from source yourself.

● Community builds

● Last resort: Separate JVM

● Isolate ClassLoaders (OSGI)

Page 16: 10 Things I Hate About Scala

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

Page 17: 10 Things I Hate About Scala

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.

Page 18: 10 Things I Hate About Scala

Workaround

Avoid overloadswhen you need

default parameters :(

Page 19: 10 Things I Hate About Scala

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.

Page 20: 10 Things I Hate About Scala

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 }

Page 21: 10 Things I Hate About Scala

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

}

}

Page 22: 10 Things I Hate About Scala

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)

Page 23: 10 Things I Hate About Scala

Why

The Scala standard library is very rich

Efforts focus more on the compiler

Page 24: 10 Things I Hate About Scala

Mitigation

Know what's going on inside

Don't assume you can't do better than the standard library.

Page 25: 10 Things I Hate About Scala

Solutions

Focus of up-coming versions

Smaller Standard Library

Page 26: 10 Things I Hate About Scala

7. Equality type unsafety

if (“foo” == 4) 1 else 2// Compiles no warning

if (4 == “foo”) 1 else 2

// Compiles with warning

Page 27: 10 Things I Hate About Scala

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

Page 28: 10 Things I Hate About Scala

Why?

● Interoperability with Java● Simplicity

Page 29: 10 Things I Hate About Scala

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"

^

Page 30: 10 Things I Hate About Scala

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

Page 31: 10 Things I Hate About Scala

Why

Some cases are difficult to infer

Need simple rules for requiring explicit types

Simple rules are overly broad

Page 32: 10 Things I Hate About Scala

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)

Page 33: 10 Things I Hate About Scala

Solution / Mitigations:

● SBT - for incremental compile (new flag)● Supply explicit return types● An area of continuous improvement in Scala

Page 34: 10 Things I Hate About 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

Page 35: 10 Things I Hate About Scala

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

Page 36: 10 Things I Hate About Scala

Thank You

Join Us