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?
If for some reason you cannot change a val to a var and still need to change its value, you can do this using reflection. This works, but it is evil. Since Scala runs on the JVM, there's no way to prevent this sort of mischief, but it goes against the fundamental design of the language. Any usage of field.
In the above syntax, the variable can be defined in one of two ways by using either the 'var' or 'val' keyword. It consists of 'variable_name' as your new variable, followed by a colon. The data type of variable is 'variable_datatype. ' which can be any valid data type.
Even from a functional programming point of view, you can use vars (or mutable objects) locally, if they don't leave the scope where they are defined.
Scala provides a nice language feature called lazy val that defers the initialization of a variable. The lazy initialization pattern is common in Java programs. Though it seems tempting, the concrete implementation of lazy val has some subtle issues.
You can do:
val whatever = if (someCondition) "final value" else "other value"
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With