36
10 Things I Hate About Scala

10 Things I Hate About Scala

Embed Size (px)

DESCRIPTION

I love Scala, I really do. I find Scala both more productive and more fun then any of the many languages I have worked with before. There are many reasons to use to Scala; however, I will not be talking about them. Instead, in this talk I will cover some of the things I find annoying or disappointing in Scala. For each I will explain the issue, why it is so, whether or not it is likely to ever change, and what, if anything, we can do about it in the mean time. The issues covered will include: Limitations on type inference Type Erasure Binary incompatibility Limitations on overloading Standard library quality And more The lecture is geared towards those who have written between 10 and 10 millions lines of Scala code.

Citation preview

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