Scala Tutorials Part #1 - Getting Started with Scala
Originally Posted On : 20 Sep 2015 Last Updated : 18 Oct 2017
Getting Started with Scala
This is the first part of a tutorial series that ill be writing on Scala. Check here for the full series.
If you are from Java there are lot of things that can be difficult to get your head around, and the most easiest way is to unlearn and re-learn them.
Let’s get started.
- Introduction to scala and environment setup
- First Hello world !!
- Reference vs Value immutability
- Immutability under the hood
- Comparing and Contrasting
- Data types in Scala
- Type inference
- Variable initialization
- Type annotations
- Type ascriptions
- Lazy val
Start with this blog post if you are new to Scala.
There are many tutorials available on the internet which talk about setting up Scala, so I am not going to walk through those again.
The developer setup that I would recommend is as follows.
- Operating System : Mac/Linux preferred
- Intellij IDEA community edition with Scala plugin installed
If you are done setting those up, then let’s begin.
Let’s directly jump into some code.
Ypu can copy this code into your Intellij IDE and then run it. If all goes well, you should see Hello World in your console.
Congratulations !! You have authored your first Hello world.
Now let’s try to understand the code. The first thing to notice, is that the whole code is inside an Object block. Java programmers might find these confusing. Hold on to this question for now, the next section deals with this in a more detailed way. Unlike Java, class names need not match with file names, not a big deal but, we do have that freedom here.
Next thing is the strange syntax of
def main(). To begin with
def is a keyword to declare methods. We will be dealing with methods in greater detail
in an upcoming tutorial.
There can be arguments for a method. In our case, it is an
Array[String]. This is similar to Java’s main method, where a string array is an argument to the main method. Can be used for startup config or any runtime variables.
This is followed by a
println() method call which prints statements on to the console.
If you are using an IDE, then you can trace the entire call by holding ctrl+click on the method (Shortcuts differ with operating systems. On the mac this is cmd+click).
Python folks should find this syntax similar, it simply prints out the given string to the console.
Semicolons are optional in scala unlike java and the compiler relies on line breaks to identify the next literal/code block.
On digging a little deeper
println() is a method present in a class called Predef.scala, which calls Console.scala’s println method which then goes all the way to calls
PrintStream.java. If you have the source code attached it shows the source code directly, otherwise the decompiler from Intellij shows the decompiled code. The print from
both Scala and Java end up in the same method call. As mentioned before, Scala is built on top of the JVM and can inter-operate with Java code seamlessly, unless there is a specific reason for a different implementation then it would be just re-inventing the wheel and hence they all rely on the existing JDK library functionality.
A simple hello world has opened up many topics to learn, three in particular
- Methods(Covered in later tutorials)
- Objects and Classes(Covered in later tutorials)
- Type inference — The reason why Scala is a statically typed dynamic language- Explained below
I should have explained data types before we jump into variables, but there are some fundamental differences that we have to understand.
val are two keywords which are used to declare variables.
var is used to declare variables that are mutable and
val to declare immutable ones. But what kind of variables are these?
For primitive data types, where does the concept of immutability come from? I encourage you to read this stackoverflow post.
Primitives by themselves are immutable i.e their type cannot be changed once declared, but their values are mutable i.e they can be changed.
val is immutable, then it cannot be changed? Is this similar to the Java final keyword or is it something related to String immutability?
Let’s look some sample code below, to help us understand better.
If you run the above code, you will notice an error at compilation itself such as reassignment to val. If you are using an IDE this will show up as you type because of pre-compilation that the IDE gives.
First thing is definitely not like String immutability where it is not visible to the programmer, and is controlled at compilation level. Next question, is it similar to final in Java?
From a bird’s eye view, this seems to be similar that once a value is assigned to it, it cannot be changed, but inside the JVM
final has nothing to do with
immutability and it is used so that classes cannot be extended and in the case of methods it cannot be overridden.
Let’s consider the below Java code to demonstrate that this is different.
If you try the same
final with primitive types, then its value cannot be changed. Does this mean primitives are immutable ?
This takes us back to the stackoverflow discussion above, but the reason why the error comes is because Java uses Pass by Value for primitive types, it makes no
sense to pass by reference since they are not objects at all. So if a variable is changed, its reference(can be said as place in memory)
changes because of the pass by value mechanism and not because that primitives are immutable.
The important point to understand is reference vs value immutability does not matter much in scala since scala does not have primitive types at all and only has objects.
Let’s take our understanding of immutability even further by examining the byte code emitted by decompiling generated scala class files.
We declare a class named
Parent and a val inside it.
On seeing the emitted bytecode, we can see that it gets translated to a java primitive type, there is nothing special going as far as the run time is concerned.
javap -c filename.class gives the below decompiled code.
It is clear that
val is just a compile time restriction and has nothing to do with the emitted byte code.
We can take this approach of reading the decompiled byte code to understand things more deeply, but in most of the cases it is not required.
Scala on the other hand also has the
final keyword which works pretty similar.
A better way to visualize the difference between a val and a final is via an example.
Let’s take a simple parent class.
Unlike java, scala can also override variables.
Now if we declare the variable
age as final in the Parent class, then it would not be possible for the Child class to override it and it would throw an error as below.
This is a real world example of where one would use
Notice that we are not breaking immutability here by overriding a val in child class. The child class creates an instance of its own just like a string in java string pool.
Scala has the same data types as in Java, with the same memory and precision.
All data types are Objects and methods can be called in them just as you would on an object.
By the time now, another question would have come up? Where are the types in the scala code?
Unlike java where we declare variables with data types and then give a variable name, scala has something called type inference(see the topics below), but don’t jump there yet, there is a reason why I separated it out from the variables section.
If you are not familiar with the term, it is nothing but the deduction of types at compile time. Hold on, isn’t that what dynamic typing means? Well no, notice that I said deduction of types, this is drastically different from what dynamically typed languages do, and another thing is it is done at compile time and not run time.
Many languages have this built in, but the implementation varies from one language to another. This might be confusing at the beginning, but it will be clearer with code examples.
Let’s jump into the Scala REPL for some experimentation.
From the image above, it is evident that there is no magic, the variables are inferred automatically to the best types they deem fit and at compile time.
Here is some more code to understand further.
Go ahead and play with these variables, you are protected from compile time type safety, so do not hesitate to mess around.
If you are curious on what classes do the variables extend, you can dig deeper and find a class called
AnyVal. This is part of an
entirely different topic of Scala’s unified type system, which is nothing but the class hierarchy.
This is dealt with in part 2 of this series with greater depth.
So whenever we are talking about immutability in scala, we are talking about reference immutability. Immutable variables have certain performance benefits and leans closer to notion of writing code without side effects.
Even though the value of a
var can be changed, its type cannot be changed.
This is akin to the behaviour in Java where you cannot assign a string to an integer. This proves that type inference is indeed at compile time.
In scala you cannot simply create a variable and leave it un-initialized.
This is a design choice that the scala language developers took. The obvious reason is not to leave variables un-initialized and also to avoid null pointer exceptions.
The only place where we don’t assign values to variables is inside abstract classes. We will see more of it when learn about classes in scala.
Scala has the facility where we can mention the type explicitly.
val y : Integer = 20
These kind of type annotations are important in public facing APIs/methods.
Note : Methods are explained in part 3
Without the type information explicitly annotated, developers consuming this will have confusion in understanding. Remember that not all languages on the JVM have type inference like java and hence a change on the type can break the client(consuming) code.
A better version would as below.
This concept not just applies to method parameters but also to variables declared using the
val keyword. The example just demonstrates the idea in a better understandable way.
Type ascriptions are something more complicated. It is process of telling the compiler of what type you would expect out of an operation that you are going to perform.
A typical use case would type casting in java.
The above code would result in a run time exception/error as below.
20 Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.Byte at JavaExample.main(JavaExample.java:14) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
In scala, when we use type ascription the code would not even compile.
There is no syntax difference between type annotation and type ascription and often results in confusion between the two topics.
We could have taken the same java route using type casting at run time.
In the above case, you can observe that it does not throw an error at compile time and it will result in the same exception stack trace i.e
java.lang.ClassCastException at run time.
Type ascriptions can be incredibly useful when performing type casting/conversion. You can check type safety at compile time rather than run time to ensure it does not result in buggy code.
As the name suggests, lazy val in scala is similar to a val, but its value is evaluated only when the variable is used.
I encourage you to try this yourself. First by commenting out
println(lines), you could see that it did not result in an error even though the file
was not there.
This is a working example where you can put in a real file on the top level of the project that you are in/ put in a specific path yourself and then the program would just print out the file content.
This is controlled at compile time, since a variable access can be know at compile time.
Very useful in situations such as a file upload window in a browser. The user may or may not upload the file, so it is best to defer/lazily evaluate until the event happens.
The Lazy keyword only applies to
val and not
var. This is because
var is not considered as a value definition since it can change its values
at runtime. It is difficult to know when it will exactly change and hence the whole concept of lazy evaluation does not make sense when it comes to
From what we have seen in this post, we can go ahead and learn the below topics.
Tutorials point arrays gives a good overview of the syntax.
Scala lang official documentation of arrays is a must read.
Arrays are the most simplistic collection type in the scala language and understanding them gives us a good head start.
The Scala REPL is a very handy tool that we can make use of for experimenting short code snippets. Make sure you checkout the Ammonite REPL which is not part of the standard Scala toolkit but much more advanced and user friendly.
This brings an end to this post, we have started with the important parts. I encourage you to re read the post to understand it completely if you haven’t and also refer relevant documentation on the internet.
Translating simple code snippets from other languages also helps.
I’ll be updating links to this article as soon as I publish pending topics that I have mentioned here. You can also subscribe if you want to keep updated.
Scala is not easy, but it is not hard either if we take one step at a time and learn things. My goal is not to teach everything, but simply point in a direction that is much less shrouded that it was before.
Keep learning and watch out for more posts