tags:

views:

325

answers:

3

I'd like to use on val to declare multiple variable like this:

val a = 1, b = 2, c = 3

But for whatever reason, it's a syntax error, so I ended up using either:

val a = 1
val b = 2
val c = 3

or

val a = 1; val b = 2; val c = 3;

I personally find both options overly verbose and kinda ugly.

Is there a better option?

Also, I know scala is very well thought out language, so why isn't the val a = 1, b = 2, c = 3 syntax allowed?

+6  A: 

It seems to work if you declare them in a tuple

scala> val (y, z, e) = (1, 2, 45)
y: Int = 1
z: Int = 2
e: Int = 45
scala> e
res1: Int = 45

Although I would probably go for individual statements. To me this looks clearer:

val y = 1
val z = 2
val e = 45

especially if the variables are meaningfully named.

Joe
+12  A: 

The trivial answer is to declare them as tuples:

val (a, b, c) = (1, 2, 3)

What might be interesting here is that this is based on pattern matching. What is actually happens is that you are constructing a tuple, and then, through pattern matching, assigning values to a, b and c.

Let's consider some other pattern matching examples to explore this a bit further:

val DatePattern = """(\d{4})-(\d\d)-(\d\d)""".r
val DatePattern(year, month, day) = "2009-12-30"
val List(rnd1, rnd2, rnd3) = List.fill(3)(scala.util.Random.nextInt(100))
val head :: tail = List.range(1, 10)

object ToInt {
  def unapply(s: String) = try {
    Some(s.toInt)
  } catch {
    case _ => None
  }
}

val DatePattern(ToInt(year), ToInt(month), ToInt(day)) = "2010-01-01"

Just as a side note, the rnd example, in particular, may be written more simply, and without illustrating pattern matching, as shown below.

val rnd1, rnd2, rnd3 = scala.util.Random.nextInt(100)
Daniel
It's worth noting that `val (a, b, c) = (1, 2, 3)` does seem to be the generally-accepted idiom for multiple assignment, preferable to separate assignment statements. At least, that has been my impression reading through community-developed code.
Daniel Spiewak
It is also worth noting that you can set multiple vals to the same value with the intuitive "val x, y, z = 42".
Mitch Blevins
+7  A: 

Daniel's answer nicely sums up the correct way to do this, as well as why it works. Since he already covered that angle, I'll attempt to answer your broader question (regarding language design)...

Wherever possible, Scala strives to avoid adding language features in favor of handling things through existing mechanisms. For example, Scala doesn't include a break statement. However, it's almost trivial to roll one of your own as a library:

case object BreakException extends RuntimeException

def break = throw BreakException

def breakable(body: =>Unit) = try {
  body
} catch {
  case BreakException => ()
}

This can be used in the following way:

breakable {
  while (true) {
    if (atTheEnd) {
      break
    }

    // do something normally
  }
}

(note: this is included in the standard library for Scala 2.8)

Multiple assignment syntaxes such as are allowed by languages like Ruby (e.g. x = 1, y = 2, z = 3) fall into the category of "redundant syntax". When Scala already has a feature which enables a particular pattern, it avoids adding a new feature just to handle a special case of that pattern. In this case, Scala already has pattern matching (a general feature) which can be used to handle multiple assignment (by using the tuple trick outlined in other answers). There is no need for it to handle that particular special case in a separate way.

On a slightly different aside, it's worth noting that C's (and thus, Java's) multiple assignment syntax is also a special case of another, more general feature. Consider:

int x = y = z = 1;

This exploits the fact that assignment returns the value assigned in C-derivative languages (as well as the fact that assignment is right-associative). This is not the case in Scala. In Scala, assignment returns Unit. While this does have some annoying drawbacks, it is more theoretically valid as it emphasizes the side-effecting nature of assignment directly in its type.

Daniel Spiewak
Great answer, I wish I could accept two answers =P.
Xavi
What if I want to declare 2 variables but do not want to assign them immediately? Like var a: MyClass, b: MyClass?
Phương Nguyễn