A question about assigning

for this code:

scala> object Traffic extends Enumeration {
     |   val Red,Yellow,Green = Value
     | }
object Traffic

How do I know which case was happened ?

  1. Value was called three times, and the generated values were assigned to the three variables.
  2. Value was called only once, but return three values, and them were assigned to the three variables.

thank you for the kind answer.

It’s the first way.

The spec says simply that it is expanded to N definitions. (End of 4.1.)

I think Enumeration was the shining moment for this syntax, but occasionally

var i, j = 0

gives it a run for its money.

I found when assigning to multi variables, the () is important. please see:

scala> mytest
val res0: (Int, Int, Int) = (1,2,3)

scala> val x,y,z = mytest
val x: (Int, Int, Int) = (1,2,3)
val y: (Int, Int, Int) = (1,2,3)
val z: (Int, Int, Int) = (1,2,3)

scala> val (x,y,z) = mytest
val x: Int = 1
val y: Int = 2
val z: Int = 3
1 Like

I almost mentioned that the “multi-definition” has nothing to do with patterns.

The other form takes a pattern, just like the case in a pattern match.

Currently, Scala 2 lints if it could fail, and Scala 3 will restrict it:

➜  ~ scala -Xlint
Welcome to Scala 2.13.8 (OpenJDK 64-Bit Server VM, Java 17.0.1).
Type in expressions for evaluation. Or try :help.

scala> val (x,y,z) = (1,2,3): Any
                            ^
       warning: match may not be exhaustive.
       It would fail on the following input: (x: Any forSome x not in (?, ?, ?))
val x: Any = 1
val y: Any = 2
val z: Any = 3

scala> (1,2,3) match { case (x,y,z) => x+y+z }
val res1: Int = 6
1 Like

That is equivalent to:

val Red= Value
val Yellow = Value
val Green = Value

Value is (IIRC) a macro that returns a new instance every time it is called.

Anyways, I wouldn’t bother too much with the Enumeration nobody uses it.
You are better with just a sealed trait and case objects.


// This one is equivalent to the previous one.
val x,y,z = mytest

// This one uses pattern matching.
val (x,y,z) = mytest

But no “case” keyword here?

Yeah, sadly no.

I had to check.

Welcome to Scala 2.13.9-20220131-161511-c4b0f17 (OpenJDK 64-Bit Server VM, Java 17.0.1).
Type in expressions for evaluation. Or try :help.

scala> for (case x <- List(42)) yield x
val res0: List[Int] = List(42)

scala> val case (x, y, z) = (42, 27, 3)
           ^
       error: illegal start of simple pattern

Note that I proposed a syntax tweak once that was rejected because it did not apply to all patterns. I think this example is an obvious shortcoming, back me up on this.

Nitpick: Value isn’t a macro. It’s spec’ed that the initializing expression is evaluated repeatedly:

scala 2.13.8> val a,b,c = math.random()
val a: Double = 0.890022405640329
val b: Double = 0.592850720032758
val c: Double = 0.5236220913137164
3 Likes

Yeah, I get the expression is evaluated every time. I just thought Value was a macro.
But I just looked at the source, and is just a method that calls another method chain that ends up calling the constructor of some protected class that mutates some variables inside the extending class… at some point I would rather prefer a macro :grimacing:

Before I was waylaid by the case question, I was going to say that not only is Enumeration not a macro, it is an early example of what you can do in a library without an enum keyword. It preceded the macro experiment. The internals are famously gnarly.

The result of a 15-year research project is that they concluded you need an enum keyword.

At least a middle-aged master’s student somewhere finally got his diploma.

Oh, you can still search “Enumeration must DIE” where Martin says, “Enumeration comes with a usage pattern. If you use it wrongly, it breaks.” I was just saying “divergent implicit expansion” spells “die”, and then everyone piled on. Then Eugene “Burmakro” Burmako added, “I think we can make Enumeration a trait macro, given we empower trait macros to read contents of host classes.” Those were heady days of innovation.

1 Like