Einstieg

Die Deklaration einer Variable beginnt mit den Schlüsselwörtern var, val oder lazy val. Anschließend wird durch einen Doppelpunkt getrennt der Typ der Variablen angegeben. Nach der Typangabe kann/muss nach einem Gleichheitszeichen "=" eine Wertzuweisung erfolgen.

var auto: String = "BMW"
val name1: Int = 3
lazy val calcuated: Int = 23*63+3
itmapa.de - X2H V 0.24

Mit dem Schlüsselwort var werden Variable definiert, deren Wert beliebig oft verändert werden kann. Dementgegen werden mit dem Schlüsselwort val unveränderliche Variablen definiert. Nach der ersten Zuweisung (bei der Deklaration) kann eine unveränderliche Variable nicht mehr verändert werden. Die Zuweisung der val-Variablen einer Klasse erfolgt bei dessen ersten Verwendung.

Mit den beiden Schlüsselwörtern lazy val werden auch unveränderliche Variable definiert, deren Wertezuweisung erst dann erfolgt, wenn die Variable zum ersten Mal verwendet wird. Dies ist z.B. sinnvoll, wenn die Belegung einer Variablen mit einer zeitaufwendigen Berechnung erfolgt und jedoch es nicht sicher ist, dass die Variable überhaupt verwendet wird.

Für die funktionale Programmierung mit Scala gilt, dass wen möglich, unveränderliche Variablen (also mit val definiert) verwendet werden. Ein Vorteil dieser Vorgehensweise liegt in der nebenläufigen Programmierung. Wenn Variablen sich nicht verändern können, besteht auch nicht das Problem der race condition1. Die aufwendige Synchronisation des Variablenzugriff entfällt damit in Scala.



Typableitung (engl. type inference)

In Scala braucht man meist nicht anzugeben, von welchem Typ eine Variable ist. Der Scala Compiler ist meistens in der Lage den Typ einer Variablen aus dem umgebenden Kontext abzuleiten und verzichtet darauf, dass dieser expliziert angegeben wird. Sieht man sich folgende Variablendefinition an, ist sofort klar, dass es sich um eine Int Variable handeln muss. Da auch der Compiler dies so erkennt, muss der Typ nicht explizit angegeben werden.

val myInt = 42
                      

Da oft die Typangaben bei der Variablendefinition fehlen, sieht Scala Quelltext oft aus als handele es sich um eine dynamisch typisierte Sprache, was Scala definitiv nicht ist.



Variablen Sichtbarkeit (engl. Scope)

In Scala können wir, wie bei den meisten anderen Programmiersprachen, nicht von jeder beliebigen Stelle im Quelltext auf eine Variable zugreifen. Um auf eine Variable zugreifen zu können, muss diese sich im Sichtbarkeitsbereich der entsprechenden Quelltextstelle befinden. Der Sichtbarkeitsbereich einer Variablen wird englischsprachig als Scope bezeichnet.

Beschäftigen wir uns zunächst auf den Variablenzugriff innerhalb derselben Klasse (gilt analog für im selbigen object). Um auf eine Variable zugreifen zu können, muss diese vor der zugreifenden Stelle definiert worden sein. Eine weitere Vorgabe ist, dass die Variablendefinition im Gleichen oder einen "höheren", umgebenen Block erfolgte.

Nachfolgend Beispiele zum Variablen-Scope.

class Scope1 {
  def method1(): Unit = {
    println(myValue)   // Error
    val myValue = 4
    println(myValue)   // OK
  }  
}
itmapa.de - X2H V 0.24

Das Beispiel Scope1 zeigt, dass eine Variable zunächst definiert werden muss, bevor auf Sie zugegriffen werden kann. Die Variable myValue wird in Zeile 4 definiert. Somit ist der Zugriff in Zeile 3 ein Fehler, wohingegen der Zugriff in Zeile 5 in Ordnung ist.



Überschatten

In Scala können Variablen in einem tieferliegenden Block, Variable eines höher liegenden Blockes überschatten. Dies geschieht, wenn die Variable im tiefer liegenden Block den gleichen Namen hat, wie der Name der Variable im höher liegenden Block.

object Scope3 {
  def main(args: Array[String]): Unit = {
    val a = 4
    println(a) 
    
    {
      val a = 5
      println(a)
    }
    
    println(a)
  }
}
itmapa.de - X2H V 0.24

Die Ausführung des Programms führt zu folgender Ausgabe auf der Systemausgabe:

          4
          5
          4
                      

Eine weitere Form des Überschattens ist das Überschatten von Variablen einer Basisklasse. Dies geschieht, indem in der Subklasse eine Variable mit dem Namen der zu überschattenden Basisklassen-Variable definiert wird. Wenn wir eine Basisklassen-Variable überschatten wollen, müssen wir der Variablen-Definition ein override voranstellen. Dies gibt an, dass wir explizit eine Basisklassen-Variable überschatten wollen und führt zu einem Fehler, sofern wir keine Basisklassen-Variable überschatten.

Das nachfolgende Beispiel zeigt das Überschatten einer Basisklassen-Variable.

object Test {
  def main(args: Array[String]): Unit = {
    val myA = new A
    val myB = new B
    
    println(myA.aValue)
    println(myB.aValue)
  }
}
          
class A {
  val aValue = 42
}
          
class B extends A {
  override val aValue = 43
}
itmapa.de - X2H V 0.24

Die Ausführung des Programms führt zu folgender Ausgabe auf der Systemausgabe:

42
43
                      
______________________________
1 Unter race condition versteht man das Problem, das zwei oder mehrere threads unsynchronisiert auf gleiche Variablen lesend und schreibend zugreifen.