views:

177

answers:

5

Why isn't it possible to have this:

def main(args:Array[String]) {
  val whatever:String // have it uninitialized here

  if(someCondition) {
     whatever = "final value" // initialize it here
  }
}

I don't understand why this shouldn't be legal.I know that I can make it a var,but why do we have to initialize the val exactly when we declare it? Doesn't it seem more logical to be able to initialize it later?

+19  A: 

You can do:

  val whatever =
    if (someCondition)
      "final value"
    else
      "other value"
Zwirb
+1  A: 

Because the purpose of 'val' is to signal to the reader (and the compiler): "This value will stay what it is initialized to until it goes out of existence"

This doesn't make much sense without initialization.

Of course one could dream up somehting like val(3) which allows three assignement to a variable, but I don't think that would be of much use.

Jens Schauder
+4  A: 

Use lazy vals like so:

def main(args:Array[String]) {
  lazy val whatever:String = if (someCondition) "final value" else "other value"

  // ...

  println(whatever) // will only initialize on first access
}
Max A.
The assignment inside the if will return Unit. An if without an else clause will also return Unit. I think you example won't compile...
Zwirb
Read before submit... You're right. Corrected.
Max A.
+3  A: 

In addition to what others have said, note that Java allows "blank final" "variables", which is a feature I kinda miss:

final Boolean isItChristmasYet;

if (new Date().before(christmas)) {
    isItChristmasYet = Boolean.FALSE;
} else {
    isItChristmasYet = Boolean.TRUE;
}

However, thanks to data flow analysis in the compiler, javac wouldn't let you leave your whatever variable unassigned if someCondition doesn't hold.

Alex Cruise
Yeah, this is what I miss from Java too.
Geo
Out of curiosity, what exactly do you gain by having the uninitialized variable pre-declared? It's not as if you could use it in any way before it's actually initialized...
Zwirb
It's a stylistic thing, I used to declare all my locals up-front at the top of their scope. I probably still would--at least sometimes--if Scala had blank vals. :)
Alex Cruise
What's wrong with `final boolean isItChristmasYet = ! (new Date().before(christmas))` ?
Kevin Wright
I knew someone would golf me. :)Nothing, but this is a trivial example in a style that's suited to more complex situations.
Alex Cruise
+5  A: 

The Java solution is actually a workaround to the problem that not all expressions return values, so you can't write this in Java:

final String whatever = if (someCondition) {
    "final value"
} else {
    "other value"
}

Increasingly, the trend in Java is to use the ternary operator instead:

final String whatever = someCondition ? "final value" : "other value"

Which is fine for that limited use case, but totally untenable once you start dealing with switch statements and multiple constructors.


Scala's approach is different here. All object construction must ultimately pass through a single "primary" constructor, all expressions return a value (even if it's Unit, equivalent to Java's Void), and constructor injection is strongly favoured. This results in object graphs being cleanly built as a Directed Acyclic Graph, and also works very nicely with immutable objects.

You also want to be aware that declaring and defining variables in separate operations is, in general, a bad practice when dealing with multiple threads - and could leave you vulnerable to exposing nulls and race conditions when you least expect them (though this isn't really a problem during object construction). The atomic creation of immutable values is just one aspect of the way in which functional languages help to to deal with concurrency.

It also means that the Scala compiler can avoid some of the hideously complicated flow analysis from the Java language spec.

As previously stated, the Scala Way™ is:

val whatever =
  if (someCondition)
    "final value"
  else
    "other value"

An approach which also scales up to other control structures:

val whatever = someCondition match {
  case 1 => "one"
  case 2 => "two"
  case 3 => "three"
  case _ => "other"
}

With a bit of Scala experience you'll discover that this style helps the compiler to help you, and you should find yourself writing programs with fewer bugs!

Kevin Wright