Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala gives no compile-time error when assigning a value to a number literal?

While learning scala I stumbled upon the following strange snippet:

package temptests

object TempTest {
  //def 2 = 123 // does not compile
  val 2 = 123 // compiles, but leads to an exception at runtime

  def main(args: Array[String]) = { // just do something to load this class
    println("Hello")
  }
}

I would expect that the compiler would throw an error on val 2 = 123 because identifiers must not start with a digit, but the code compiles without a warning. However, at runtime it immediately throws an Exception:

Exception in thread "main" java.lang.ExceptionInInitializerError at temptests.TempTest.main(TempTest.scala) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) Caused by: scala.MatchError: 123 (of class java.lang.Integer) at temptests.TempTest$.(TempTest.scala:5) at temptests.TempTest$.(TempTest.scala) ... 6 more

I am just curious: how is val 2 = 123 understood by Scala? Why is there no compile-time error?

like image 730
cubic lettuce Avatar asked Mar 19 '16 13:03

cubic lettuce


2 Answers

I am just curious: how is val 2 = 123 understood by Scala?

You can think of val 2 = 123 as:

123 match {
    case 2 => 2
}

The variable name part in Scala isn't always a simple name, it can also be a pattern, for example:

val (x, y) = (1, 2)

Will decompose 1 and 2 to x and y, respectively. In scala, everything which is allowed after a case statement is also allowed after val and is translated to a pattern match.

From the specification (emphasis mine):

Value definitions can alternatively have a pattern as left-hand side. If p is some pattern other than a simple name or a name followed by a colon and a type, then the value definition val p = e is expanded as follows:

(Skipping to the relevant example):

If p has a unique bound variable x:

val x = e match { case p => x }

This is the reason the compiler doesn't emit a compile time error. There is a lengthy discussion of the subject in this google group question.

like image 68
Yuval Itzchakov Avatar answered Oct 15 '22 20:10

Yuval Itzchakov


The left hand side of a val declaration can be a pattern. See scala language documentation.

so

val 2 = 123

can be written as

123 match {
  case 2 => 2
}

which gives a match error.

In real life this is mostly used to extract tuples to readably local vals:

val test = ("Foo", 30)
val (name, age) = test
like image 20
Sascha Kolberg Avatar answered Oct 15 '22 21:10

Sascha Kolberg