Basic Constructs of Scala

Basic Constructs of Scala

Type Inference

First thing to understand about Scala is that it is a Dynamically Typed Language which means that the data type of the values or variables are deduced at runtime.

scala> val a = 10.0
a: Double = 10.0

 

Although it is dynamically types, you can still specify the datatype.

scala> val b: Double = 10.0
b: Double = 10.0

 

Being dynamically typed your code is less verbose but one drawback could be that you can face some runtime issues which would have otherwise been checked at the compile time in other statically types language like Java.

 

Primary base classes in Scala:
Any: It is the main base class like the Object class of Java

scala> def anyFunc(x: Any) = println(x)
anyFunc: (x: Any)Unit
scala> anyFunc(1)
1
scala> anyFunc(Array(1,2))
[I@516ebdf8

AnyVal: Sub-class of Any and base for all Java Value types like int, double, boolean and char types. It’s similar to the primitive types in Java

scala> def anyValFunc(x: AnyVal) = println(x)
anyValFunc: (x: AnyVal)Unit
scala> anyValFunc(1)
1
scala> anyValFunc(Array(1,2))
:9: error: type mismatch;
found : Array[Int]
required: AnyVal
Note that implicit conversions are not applicable because they are ambiguous: both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A] and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A] are possible conversion functions from Array[Int] to AnyVal anyValFunc(Array(1,2))

AnyRef: Sub-class of Any and base for all Java Reference types like strings, collections and arrays

scala> def anyRefFunc(x: AnyRef) = println(x)
anyRefFunc: (x: AnyRef)Unit
scala> anyRefFunc(Array(1,2))
[I@1305c126
scala> anyRefFunc(1)
:9: error: type mismatch;
found : Int(1)
required: AnyRef
Note: an implicit exists from scala.Int => java.lang.Integer, but methods inherited from Object are rendered ambiguous. This is to avoid a blanket implicit which would convert any scala.Int to any AnyRef. You may wish to use a type ascription: `x: java.lang.Integer`. anyRefFunc(1)

 

String Interpolation

It is the embedding of placeholders within string constants. The placeholder can be replaced by constant value strings or by expressions which are evaluated to find the final value.

scala> val pi = 3.14
pi: Double = 3.14
scala> s"pi is $pi"
res16: String = pi is 3.14
scala> s"Round of pi is ${22/7}"
res18: String = Round of pi is 3

 

Data Immutability

By default the data entities in Scala are immutable which means they are initialized once and if you try to change their value you will get error.

scala> val temp = 10
temp: Int = 10
scala> temp = 20
:8: error: reassignment to val temp = 20

 

If you have the need to modify the value then Scala provides you a keyword ‘var’ for variables. You are allowed to change their value.

scala> var temp = 10
temp: Int = 10
scala> temp = 20
temp: Int = 20

 

Expressions

Expressions are the block of code which return a value. They are enclosed within curly braces and can also replace functions. Read more about them from the perspective of functional programming in the blog Understanding Functional Programming with Scala.

Although the return data from an expression or function is generally a value, we sometimes need a null type to return. In Scala that is represented by None. None is value in Scala and is similar to the use of NULL in Java.

Another special return type is Nothing which is represented by starting and closing round braces (). Nothing is a sub-type of AnyVal and is returned by Scala when there is no return data or expression specified. It is similar to VOID in Java. One more point to note is that Nothing is just a type so it cannot be instantiated.

 

If/Else Expressions

If/Else is the conditional expression. It is similar to how it is used in other languages except that in both True and False blocks we specify an expression which means a value is always returned from If/Else block.

scala> val age = 15
age: Int = 15
scala> if (age > 18) {"adult"} else {"not an adult"}
res19: String = not an adult

 

Even if you only have If block then also Nothing value will be returned.

scala> if (age > 18) {"adult"}
res20: Any = ()

 

For Loop

First lets look at the standard way a for loop is used to iterate through a collection:

scala> val age = List(10,20,15,25)
age: List[Int] = List(10, 20, 15, 25)
scala> def checkAge(x: Int) = if (x > 18) {true} else {false}
checkAge: (x: Int)Boolean
scala> for(a <- age) { println(checkAge(a)) }
false
true
false
true

 

Another way to iterate is using an index on the collection. Find below another way to iterate over the age collection. Note, since the index starts with 0 we only iterate till one size less.

scala> for(i <- 0 to age.size-1) { println(checkAge(age(i))) }

 

Another option is to use the ‘until‘ which by default leaves out the last counter value.

scala> for(i <- 0 until age.size) { println(checkAge(age(i))) }

 

You can also add a condition in the for-loop so that the loop body only executes when the condition is true.

scala> for(a <- age if a > 18) { println(checkAge(a)) }
true
true

 

For loops can be nested and you can specify all the nested loops in one condition.

scala> for {i <- 0 to 1
| j <- 0 to 1} { println(i + "," + j) }

0,0
0,1
1,0
1,1

 

For loops can also be used as expressions which although iterate over a collection but in response return another collection whose each element is the result of the for loop expression evaluated using input expression. The keyword yield is used to transform a standard loop.

scala> val ageCheckList = for(a <- age) yield { checkAge(a) }
ageCheckList: List[Boolean] = List(false, true, false, true)