8 min read

In this article by Md. Rezaul Karim and Sridhar Alla, author of Scala and Spark for Big Data Analytics, we will discuss the basic object-oriented features in Scala. In a nutshell, the following topics will be covered in this article:

  • Variables in Scala

(For more resources related to this topic, see here.)

Variables in Scala

Before entering the depth of OOP features, at first, we need to know the details of the different types of variables and data types in Scala. To declare a variable in Scala, you need to use the var or val keywords. The formal syntax of declaring a variable in Scala is as follows:

val or var VariableName : DataType = Initial_Value

For example, let’s see how we can declare two variables whose data types are explicitly specified as shown:

var myVar : Int = 50
val myVal : String = "Hello World! I've started learning Scala."

Even you can just declare a variable without specifying the data type. For example, let’s see how to declare a variable using var or val:

var myVar = 50
val myVal = "Hello World! I've started learning Scala."

There are two types of variables in Scala–mutable and immutable–that can be defined as this:

  • Mutable: The ones whose values you can change later
  • Immutable: The ones whose values you cannot change once they have been set

In general, for declaring a mutable variable, the var keyword is used. On the other hand, the val keyword is used for specifying an immutable variable. To see an example of using the mutable and immutable variables, let’s consider the following code segment:

package com.chapter3.OOP 
object VariablesDemo {
  def main(args: Array[String]) {
    var myVar : Int = 50 
    valmyVal : String = "Hello World! I've started learning Scala."  
    myVar = 90  
    myVal = "Hello world!"   
    println(myVar) 
    println(myVal) 
  } 
}

The preceding code works fine until myVar = 90, since myVar is a mutable variable. However, if you try to change the value of the immutable variable (that is, myVal), as shown earlier, your IDE will show a compilation error saying that reassignment to val as follows:

Figure 1: Reassignment of immutable variables is not allowed in Scala variable scope

Don’t worry looking at the preceding code with object and method! We will discuss classes, methods, and objects later in this article, then things will get clearer.

In Scala, variables can have three different scopes depending on the place where you have declared them:

  • Fields: Fields are variables belonging to an instance of a class of your Scala code. The fields are, therefore, accessible from inside every method in the object. However, depending on the access modifiers, fields can be accessible to instances of the other classes.
As discussed earlier, object fields can be mutable or immutable (based on the declaration types, using either var or val). However, they can’t be both at the same time.
  • Method arguments: When the method is called, these variables can be used to pass the value inside a method. Method parameters are accessible only from inside the method. However, the objects that are being passed in may be accessible from the outside.
It is to be noted that method parameters/arguments are always immutable, no matter what is/are the keywords specified.
  • Local variables: These variables are declared inside a method and are accessible from the inside the method itself. However, the calling code can access the returned value.

Reference versus value immutability

According to the earlier section, val is used to declare immutable variables, so can we change the values of these variables? Also, will it be similar to the final keyword in Java? To help us understand more about this, we will use this code snippet:

scala> var testVar = 10
testVar: Int = 10

scala> testVar = testVar + 10
testVar: Int = 20

scala> val testVal = 6
testVal: Int = 6

scala> testVal = testVal + 10
<console>:12: error: reassignment to val
       testVal = testVal + 10
               ^
scala>

If you ran the preceding code, an error at compilation time will be noticed, which will tell that you are trying to reassign to a val variable. In general, mutable variables bring a performance advantage. The reason is that this is closer to how the computer behaves and introducing immutable values forces the computer to create a whole new instance of an object whenever a change (no matter how small) to that instance is required.

Data types in Scala

As mentioned Scala is a JVM language, so it shares lots of commonalities with Java. One of these commonalities is the data types; Scala shares the same data types with Java. In short, Scala has all the data types as Java, with the same memory footprint and precision. Objects are almost everywhere in Scala and all data types are objects; you can call methods in them, as illustrated:

Sr.No Data type and description
1 Byte: An 8 bit signed value; range is from -128 to 127
2 Short: A 16 bit signed value; range is -32768 to 32767
3 Int: A 32 bit signed value; range is -2147483648 to 2147483647
4 Long: A 64 bit signed value; range is from -9223372036854775808 to 9223372036854775807
5 Float: A 32 bit IEEE 754 single-precision float
6 Double: A 64 bit IEEE 754 double-precision float
7 Char: A 16 bit unsigned Unicode character; ranges from U+0000 to U+FFFF
8 String: A sequence of Chars
9 Boolean: Either the literal true or the literal false
10 Unit: Corresponds to no value
11 Null: Null or empty reference
12 Nothing: The subtype of every other type; it includes no values
13 Any: The supertype of any type; any object is of the Any type
14 AnyRef: The supertype of any reference type
Table 1: Scala data types, description, and range

All the data types listed in the preceding table are objects. However, note that there are no primitive types as in Java. This means that you can call methods on an Int, Long, and so on:

val myVal = 20
//use println method to print it to the console; you will also notice that if will be inferred as Int
println(myVal + 10)
val myVal = 40
println(myVal * "test")

Now you can start playing around with these variables. Now, let’s get some ideas on how to initialize a variable and work on the type annotations.

Variable initialization

In Scala, it’s a good practice to initialize the variables once declared. However, it is to be noted that uninitialized variables aren’t necessarily nulls (consider types such as Int, Long, Double, and Char) and initialized variables aren’t necessarily non-null (for example, val s: String = null). The actual reasons are the following:

  • In Scala, types are inferred from the assigned value. This means that a value must be assigned for the compiler to infer the type (how should the compiler consider this code: val a? Since a value isn’t given, the compiler can’t infer the type; since it can’t infer the type, it wouldn’t know how to initialize it).
  • In Scala, most of the times, you’ll use val since these are immutable; you wouldn’t be able to declare them and initialize them afterward.

Although Scala language requires that you initialize your instance variable before using it, Scala does not provide a default value for your variable. Instead, you have to set up its value manually using the wildcard underscore, which acts like a default value, as follows:

var name:String = _

Instead of using names such as val1, and val2, you can define your own names:

scala> val result = 6 * 5 + 8
result: Int = 38

You can even use these names in subsequent expressions, as follows:

scala> 0.5 * result
res0: Double = 19.0

Type annotations

If you used the val or var keyword to declare a variable, its data type will be inferred automatically according to the value that you assigned to this variable. You also have the luxury of explicitly stating the data type of the variable at declaration time:

val myVal : Integer = 10

Now, let’s see some other aspects that will be needed while working with the variable and data types in Scala. We will see how to work with type ascription and lazy variables.

Type ascriptions

Type ascription is used to tell the compiler what types you expect out of an expression, from all possible valid types. Consequently, a type is valid if it respects the existing constraints, such as variance and type declarations; it is either one of the types the expression it applies to “is a” or there’s a conversion that applies in scope. So technically, java.lang.String extends java.lang.Object; therefore, any String is also an Object. Consider the following example:

scala> val s = "Ahmed Shadman" 
s: String = Ahmed Shadman

scala> val p = s:Object 
p: Object = Ahmed Shadman 
 
scala>

Lazy val

The main characteristic of a lazy val is that the bound expression is not evaluated immediately, but once on the first access. Here lies the main difference between val and lazy val. When the initial access happens, the expression is evaluated and the result bound to the identifier of the lazy val. On subsequent access, no further evaluation occurs; instead, the stored result is returned immediately. Let’s look at an interesting example:

scala> lazy val num = 1 / 0
num: Int = <lazy>

If you see the preceding code in Scala REPL, you will note that the code runs very well without giving any error even though you divided an integer with 0! Let’s look at a better example:

scala> val x = {println("x"); 20}
x
x: Int = 20

scala> x
res1: Int = 20
scala>

This works, and you can access the value of the x variable when required later on. These are just a few examples of using lazy val concepts. The interested readers should access https://blog.codecentric.de/en/2016/02/lazy-vals-scala-look-hood/ for more details.

Summary

The structure code in a sane way with classes and traits enhance the reusability of your code with generics and create a project with standard and widespread tools. Improve on the basics to know how Scala implements the OO paradigm to allow building modular software systems.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here