By developers for developers.

Scala for the Intrigued

Sensible Typing and Optional Items

by Venkat Subramaniam

In this second installment of this series on the Scala programming language, Venkat shows how Scala’s static typing leads to low ceremony programming.

In this second part of the series we will look at the statically typed nature of Scala and its low ceremony.

Java programmers are used to static typing. Scala is also statically typed. However, it employs type inference to figure out types at compile time. So for the most part, you don’t have to specify type information. While Scala provides type inference, it does not go to extremes to determine the type (like F#, for example, which will analyze the method body to figure out types of parameters). Scala type inference reduces the number of keystrokes you have to type and reduces noise in code without compromising readability or understandability.

Let’s first look at how we’d define a variable, set its type, and assign it an initial value. Then we can look at what type inference buys us.

var greet : String = "hello"

You use var to define a mutable variable, a variable whose value can change (true to its varying nature). When defining a variable, use a colon to separate the name of the variable from its type. Finally you can assign a value to the variable using the all-too-familiar equals operator.

Let’s extend that example to change the variable’s value and print the new value.

var greet : String = "hello"

println(greet)

greet = "howdy"

println(greet)

We initialized the variable greet to “hello” and then changed it to “howdy.” The output from the code is shown below:

hello

howdy

At this point if you listen keenly you may hear Scala laughing at the redundancy in typing. Scala already knows that greet is of type String from the fact that its value was initialized to “hello.” So, the : String part is redundant, and you can omit it:

var greet = "hello"

println(greet)

greet = "howdy"

println(greet)

Scala infers the type of the variables at compile time. If Scala notices any ambiguity or errors, it will report right away and will not run any part of the code.

Let’s see what happens if we try to set a value of the greet variable to something not compatible with its type:

var greet = "hello"

println(greet)

greet = 1

println(greet)

When you try to run this script, you will get an error:

error: type mismatch;

found : Int(1)

required: java.lang.String

greet = 1

Scala is quick to tell us that the value 1 we’re assigning to the variable does not match with the type String, the type which it inferred at the point of declaration.

I must acknowledge that this can be a blessing or a curse, depending on how you look at it. numbers is inferred as a List[Int] based on the values you present to the list. If all the values are of the same type, then this is not a concern. However, if you mix the values of different type, you will not get any error. For example:

val list1 : List[Int] = List(1, "2", 3)

will result in an error:

error: type mismatch;

found : java.lang.String("2")

required: Int

val list1 : List[Int] = List(1, "2", 3)

However, if you leave out the type in the declaration, as in:

val list1 = List(1, "2", 3)

you will not get any errors and the type of the list1 reference will be inferred as List[Any]. If you did not expect that and you mixed the type for the value in error, the type inference will not have alerted you and will not have acted in your favor. So use caution when relying on type inference.

Type inference is also convenient when defining function values. We will discuss function values later in this series, but for now think of them as anonymous code blocks. To iterate over a list of numbers you can pass a function value to the internal iterator:

numbers.foreach { e : Int => print(e) }

With numbers defined as List(1, 2, 3), this code will print

123

as output. Scala is performing type checking to ensure that the type of the parameter e in the anonymous code block (function value) matches the type of the elements in the list numbers. If you declare a different type, you will get a clear compilation error, as in:

numbers.foreach { e : Double => print(e) }

and the error reported by the compiler is:

error: type mismatch;

found : (Double) => Unit

required: (Int) => ?

numbers.foreach { e : Double => print(e) }

^

Scala reports that it found a parameter of type Double when Int was required.

You can avoid this journey entirely by letting Scala infer the type for the parameter of the function value:

numbers.foreach { e => print(e) }

This code will also produce the output

123

however it is less noisy, since we let Scala infer the type. At this point Scala checks the signature of the function that the foreach function expects as parameter and infers the type of the parameter e to be the same. You will appreciate the benefit this conciseness offers even more when the anonymous code block has more parameters.

If you make a mistake and treat the parameter as some other type, Scala will give you an error at the point of usage. For example, suppose you mistook the parameter to be a String and decided to call the length method on it:

numbers.foreach { e => println(e.length) }

Scala will give you an error that clearly explains the problem as it sees it:

error: value length is not a member of Int

When defining anonymous code blocks or function values, you can safely leave out the type declaration. When you are defining functions or methods, however, you’ll find that Scala requires you to specify the type. Where possible, I prefer to provide meaningful variable names and let the context tell me what the type is, allowing Scala to infer the type. Coming from Java you may find that this takes a bit of getting used to, but once you get a handle on it, you’ll find the reduced noise quite refreshing.

We saw how specifying the type is optional as Scala infers the type for us wherever possible. Quite a few more things are optional in Scala, depending on the context:

class

dot and parenthesis

parameter names

return

semicolon

try-catch

Let’s quickly look at each of these.

optional class: In the first article of this series we saw how writing a class is optional. Scala allows you to write simple scripts and does not force you to create a class.

optional dot and parameter: We’re used to following a target object with a dot to indicate method invocation, as in lower.to(upper);. If we follow that convention, a simple loop will look like this:

for(index <- lower.to(upper)) { print(index) }

However, that’s quite noisy and not as readable as the following:

for(index <- lower to upper) { print(index) }

When invoking methods on instances, you may drop the dot and the parentheses and enjoy the added fluency that Scala provides.

optional parameter names: When defining simple function values or code blocks, if you are merely passing the parameters to another function, you can let Scala do that for you. For example, instead of writing

numbers.foreach { e => println(e) }

you can write

numbers.foreach { println }

Scala analyzes the parameter your code block should receive and analyzes the function you call in it and chains the parameter of your code block as the arguments for the function you call within the code block.

You can go a step further and make use of the optional dot to write

numbers foreach println

optional return: The last expression executed within a function is returned and you don’t have to place an explicit return. So the following

def doubleValue(number : Int) : Int = return number * 2

is equivalent to

def doubleValue(number : Int) : Int = number * 2

Scala punishes us a little for placing the return by requiring us to specify the return type of the function. However, if you drop the return keyword, you can also drop the type information:

def doubleValue(number : Int) = number * 2

optional semicolon: You’re not required to end each statement or expression with a semicolon, Scala inserts semicolons automatically. Unlike Java code, Scala code usually has few semicolons.

optional try-catch: The Scala compiler does not distinguish checked vs. unchecked exceptions. If you’d like to handle an exception, place a try-catch block around the piece of code. If you’d rather let the caller of your code deal with it, simply do nothing and the exception will propagate to the caller. This eliminates clutter in the code and also avoids the temptation to suppress exceptions to silence the compiler.

When programming in Scala you will see these optional items interplay nicely to reduce code and clutter and make the code more expressive.

Until next time, I hope you play with Scala to enjoy its expressive and concise style.

Dr. Venkat Subramaniam is an award-winning author, founder of Agile Developer, Inc., and an adjunct faculty at the University of Houston.

He has trained and mentored thousands of software developers in the US, Canada, Europe, and Asia, and is a regularly-invited speaker at several international conferences. Venkat helps his clients effectively apply and succeed with agile practices on their software projects.