26

I found it interesting that this puzzler, specifically this code:

val (i, j): (Int, Int) = ("3", "4")

Fails at runtime in Scala 2.9.1, but fails at compile time w/ 2.10 M3(which is great). I try to track what's coming in new Scala releases, but I'm unable to connect the dots here. What improvement led to this more precise behavior?

Adam Rabung
  • 5,232
  • 2
  • 27
  • 42
  • 2
    I have no idea why that would fail at runtime and not compile time in any version of Scala. – Dan Burton May 17 '12 at 04:05
  • I guess that it just slipped through a test somewhere. It's actually kind of funny: I was talking to a Python devotee yesterday about how great Scala is, only to find today that Scala fails when presented with an assignment that's almost classic Python in nature. – pmcs May 17 '12 at 05:22
  • 1
    `val (i:Int, j:Int) = ("3","4")` fails at compile-time in 2.9.1 – Rogach May 17 '12 at 05:37
  • 1
    @pmcs - Scala *is* great! But nothing is perfect ;) – Rogach May 17 '12 at 05:37
  • 6
    @Dan - assignment in scala is done as follows: `val p = x` where `p` is any pattern. The pattern `x: (Int, Int)` is a runtime type check, but remember at runtime, due to **type erasure**, the type `(Int, Int)` is really just `Tuple2`. This is why it compiles but falls over with a class cast exception at runtime – oxbow_lakes May 17 '12 at 07:03
  • 5
    @pmcs The closest Scala equivalent to python is: `val (i,j) = ("3","4")`. It just works. And as in python you will need to convert the strings in ints if you need arithmetic. – paradigmatic May 17 '12 at 07:53
  • @pmcs You realize that the whole point of the example is that it _should_ fail, right? If Python accepts it, then it's doing worse than both Scala 2.9.1 (fails at runtime) and Scala 2.10 (fails at compile time). But I suppose it would fail in Python as well, as soon as you try to use `i` or `j` as numbers. – Daniel C. Sobral May 17 '12 at 13:34
  • 1
    @oxbow_lakes Why is that pattern a *runtime* check unlike ML, OCaml, F#, Haskell etc.? For example, `let (a, b) : int * int = "3", "4"` gives a type error in OCaml or F#. – J D May 18 '12 at 13:41
  • 1
    @JonHarrop: interesting point; I guess it's a consequence of allowing arbitrary pattern matching. For instance, val Foo((a, b): (Int, Int)) = ("3", "4") can be valid, for instance if Foo.unapply has type Any => Option[Any]. In that case, the typecheck _must_ be done at run-time. I don't think you can express this without subtyping, and none of the languages you mention has user-defined extractors AFAIK. Still, in some cases the typecheck can be proven earlier to fail, so currently Scala is just as good in this example. – Blaisorblade Jul 27 '12 at 01:03

2 Answers2

16

In scala 2.10, the pattern matcher has had a complete re-write and is now the virtualized pattern matcher. Read more about it!

Community
  • 1
  • 1
oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • 1
    Well, the virtual part is just internal unless you pass a flag, iirc. The actual output is not virtual (ie, is not implemented as calls on a monad). – Daniel C. Sobral May 17 '12 at 13:28
  • 1
    Well, yes. But the main point is that it represents a complete re-write (which would explain why its behaviour may have changed) – oxbow_lakes May 17 '12 at 15:03
  • Why should the pattern matcher make any difference to this example? I would expect the compiler to reject the code during type checking before it ever got to the pattern matcher... – J D May 18 '12 at 13:43
10

The thing that's going on is that the new pattern matcher is much easier to enhance and maintain, because it's not a rats nest piece of code. The following example code should also exhibit the same change:

("3", "4") match { case (i, j): (Int, Int) => /* whatever */ }

What's happening is Scala understanding at compile time that the pattern can never be matched.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681