Scala Tutorial by Example - Platform free

Start a better code and better engineered work with Scala.

Scala Tutorial by Example - Platform free

This is a gentle introduction to programming in Scala. This tutorial is still under active development. In case you happen to have an interest in completing the tutorial by providing your working example, then let's get connected.

Let's start by answering the question of why I want to learn Scala.

Why Scala? The real drivers for getting into it!

Scala is among the top 10 most popular programming languages. It helps you elegantly solve real-world problems in many ways. It allows you to combine the concepts of functional programming and object-oriented design.

The reasons there are so many high-profile Scala users, like Twitter and LinkedIn, eventually boil down to runtime performance and stability as well as the availability of libraries for building concurrent and distributed applications (using actors). In addition, Scala programming significantly cuts down the development time of an application and its maintenance expense.

If I want to go a bit more into detail, I would say that Scala encourages the usage of immutable data structures, making it more error-prone, safer, and perhaps easier to understand. Moreover, Scala runs on Java Virtual Machine (JVM) and it plays well with existing Java applications, meaning that a lot of libraries can be easily used with Scala. JVM is known for its monitoring, garbage collecting, and load balancing tools.

If you want to explore the world of functional programming then Scala is a perfect choice without completely disregarding the choice of object-oriented programming.

scala for scala hackers

Note: If you are new to the concept of functional programming, it is often recommended to start with Haskell, and play with it for a while. The point is that in Haskell, you cannot drift into non-functional programming. So perhaps you can do a quick but thorough brush-up to rewire your brain. The best place to practice some Haskell is Learn You a Haskell for Great Good!

For my tutorial, I will try to follow the structure presented here, but from time to time I may deviate from it. I will also borrow some of the nice visualizations presented there.

Some facts about Scala

• In Scala usage of semicolons is mandatory, and you need to use them only when you have multiple statements per line.

• Scala offers better concurrency by using immutability and actors. (I will make this point more clear as we go)

• Scala runs on both Java and. NET. For more info have a look here

Now let's jump right into the installation process.

Installation

Let’s first try to install Scala on a Linux machine and set up a Jupiter notebook for IDE. The first thing we need to install or upgrade is JVM. So go to www.java.com/en/download. To install Java you may like to follow the instructions provided here.

If you are on Mac, it’s pretty easy to install Scala. You need to go to brew.sh and install Homebrew. Now inside your terminal just type $ brew install scala and that’s it.

For Linux, you need to download the binaries and unpack the archive from here. Unpack the .tar file by tar zxvf fileNameHere.tgz . Then you need to add Scala and Scalac to your path by editing .bashrc .

export SCALA_HOME=/home/cloudera/workspace/scala/scala-2.12.1/
export PATH=$SCALA_HOME/bin:$PATH

The best choice for me is just to download a Cloudera VM. If you are a data scientist or if you just would like to start with data science and analytics then I would recommend you go and get one of the Cloudera VMs. It comes prepacked with most of the big data tools, like Hadoop, Hue, Hive, HBase, and Impala. Also, Scala is installed in it, where you can call spark jobs through Scala or Python APIs. If you have downloaded a Cloudera VM, then the only thing you need to do is just to type in spark-shell, and you are going to your first Scala project.

And now if you are interested in running your Scala application in Jupiter Notebook, follow the instructions here on how to install Scala Kernel for Jupyter.

You may also like to use IntelliJ IDEA, which I recommend if you are coding for a big Scala project.

OK, enough on the installation process and facts on Scala. Let’s begin with some coding.

Basics of Scala

Here I would like to start with some very basic codes in Scala, just to give you the feeling that Scala is a language that shares a lot of similarities with other languages. At the same time, I would to emphasize that Scala is a paradigm shift. We will cover the fundamentals of Scala in another section.

// This is the way to put comments on your code. You can put multiline comment by opening /* and closing */. This is similar to way we put comments in Java.
// Now let’s do some basic math. In your command line just type in
2 + 2 * 2
// This will create a variable res0 with type Int and value of 6. Now you can used this res0 variable in the rest of your code.
"The value of res0 is: " + res0
// And what you get in return is: res1: String = The value of res0 is: 4. So now not only we have the results, but the result is also store in a variable res1 with type String.
// Note that when a value is assigned to variable, it cannot be changed. So in you type in
res0 = 2
// Then you will get an error message, informing you that the value of the variable cannot be changed.
// If you need to define a variable that needs to be changed, then you need to use var.
var myMessage = "Make sure to import the necessary libraries."

Make big numbers

Like all other programming languages, if you use big numbers, you will lose the precision. To prevent that you can use BigDecimal and BigInt.

var myInt = BigInt("1234567890123456789012345678901234567890")
var myDecimal = BigDecimal("10.1234567890123456789012345678901234567890")

Generate random numbers with Scala

To get a random number drawn from a uniform distribution bounded between 0 and one:

random

You can easily generate random inciter numbers between 0 and 6:

(random * 6 + 1).toInt

Some Math

In Scala, you cannot do ++ or --. However, you can do the following:

myInt = 12
myInt += 4
myInt -= 2
myInt *= 10

First, let's import a library in Scala and do some simple math.

import scala.math._
// This will import all the
abs(-1) // for abs value
ceil(-1.2)
round(-1.2)
floor(-1.2)
toRadians(45)
toDegrees(0.78)
sqrt(10)
pow(10,2)
cbrt(12) // for cube root
exp(10)

Function definition

def add(a:Int, b:Int):Int = a + b
val sum:Int = add(2, 10) //val specifies immutability of Int sum
println("The value of the sum is: " + sum)

As you have noticed, pretty much anything that appears after : specifies the type. Also, there is no explicit return statement. The value of the last expression is always returned automatically. Check the next piece of code:

def MyFunc(a:Int):Int = {
    a + 1
    a + 2
    a + 3
}
val p = MyFunc(10) // Here I deliberately dropped the type of val p, and Scala does not complain about it.
println("The value of p is: " + p)

Conditionals in Scala

Now let us jump into Scala’s If...Else Expression Blocks and Loops.

Type-level programming in Scala (coming soon)

Fundamentals of Scala

In this section, I would like to cover the unique part of Scala, the side that stands apart from the crowd.

In types we trust!

In Scala, you can trust your code more than the codes developed in other languages. You want a coding platform where in there if your code compiles, then you should be fine to go. In Scala you know if your types are wrong at compile time not at runtime.

Functions are first-class citizens in Scala

One of the concepts in Scala that looks very new to Java users is that in Scala functions are types. In Scala, just like the recent developments in Java 8, you can pass functions around. Not something that we were used to. In your function, you can be very specific about what type of input you expect the function to accept and what should be the return type.

So in Scala function types are based on a) The number and the type of input parameters and b) The return type. So in the MyFunc function that we have defined above (here), the function takes an Int and returns a type Int. As another example, we may have a function that takes two Int as input and returns a string:

def makeString(x: Int, y: Int): String = x + " and " + y

I could have defined the above function like this:

val makeString: (Int, Int) => String = (x, y) => x + " and " + y

The above code says that I'm going to define a function named MakeString that takes two integers and generates and returns a String. Those two incoming parameters are Integers x and y and the return String is x + " and " + y. Now I can try the above code on REPL:

scala> makeString(2,4)
res1: String = 2 and 4

Note that in Scala the last executable statement of a function is what it will return.

Recursion and Stack Overflow

For-each loops as well as while loops, do loops, etc are all iterations. Java is designed to accommodate iterations, and it's not very well at handling recursions. In contrast, Scala, being a functional language, avoids iterations and more gears toward recursion.

Let us write a function that computes the sum of the first natural n natural numbers:

def sumn(n: Int): Int = {
    if (n == 0) 0 else n + sumn(n-1)
}
println("The sum of first 10 natural numbers is: " + sumn(10))

By increasing n, we will reach a point where we will get a stack overflow error. Let us see how Scala overcomes the limitations of the call stack. Let's rewrite the above code, this time using the concept of Tail Calls to avoid the stack overflow message:

def sumn(n: Int, acc: Int): Int = {
    if (n == 0) acc else sumn(n-1, acc + n)
}
println("The sum of first 10 natural numbers is: " + sumn(10, 0))

If you need more clarifications on this then please visit here.

Higher order function in Scala

A function is eligible to be called a higher order if It can be passed a function OR It returns a function

def sqrt(x: Int)= x * x

def sum(f: Int => Int, a: Int, b: Int): Int = {
    if (a == b) f(b) else f(a) + sum(f, a + 1, b)
}

println("The sum of square of number sbetween 10 and 20 is: " + sum(sqrt, 10, 20))

In the above example, the function sum is called a higher-order function.

Anonymous functions in Scala

Let's say that we need to compute the sum of the square of numbers between two integers, a and b.

def sum(f: Int => Int, a: Int, b: Int): Int = {
    if (a == b) f(b) else f(a) + sum(f, a + 1, b)
}
println("Here the assumpotion is that a is always smaller than b. I'm not cheking if that assumption is indeed true or not!")
println("The sum of squares netween 10 and 20 is: " + sum(x => x*x, 10, 20))

In this example x => x*x is an anonymous function that takes x as an input and returns x^2.

Note: Can you explain why the code does not compile properly if I replace x\x with scala.math.pow(x,2)*?

Map, Filter, and Reduce: The methods of collections

Let's build an array of type Int that covers all of the integers from 100 to 500. The task is to:

  • Compute the square root of each element of the array

  • Filter the ones that are bigger than 450.

  • Compute the sum of all the elements of the vector.

Now let's see the Map, Filter, and Reduce in action.

import Array._
var A0 = range(100, 500)
val A1 = A0.map(x => x*x)
val A2 = A0.filter(x => x > 450)
val A3 = A0.reduce((x, y) => x + y)

The above code is self-explanatory. Let's add another example, this time with Vectors. Vectors are built for accessing its elements in constant time. Their elements can be modified easily, a feature that makes them easier to use. The comments in the code explain the process:

// Lets begin by making an empty Vector.
val v = scala.collection.immutable.Vector.empty
// Now we will make three Vectors, v1, v2, and v3
val v1 =  v :+ 1 :+ 2 :+3
val v2 = Vector(2, 2, 3);
val v3 =  Vector(3, 2, 3)
// The idea here is to compute the sum of v1, v2 and v3
val sum = Vector(v1, v2, v2).transpose.map(_.sum)

Pattern matching in Scala

If you tag a .r to any string, scala will make that string into a regular expression.

Define a class in Scala

Ok, now we have everything in place to get more real and implement our first scala class. The idea here is borrowed from the world of the Internet of Things (IoT), the buzzword that we hear a lot these days.

Let's imagine that an LED is connected to the internet. We would like to check its status, and we want to be able to turn it on and off. Also, we want to know the time since the last change in its status. To implement the idea let's create the Time class.

import java.util.Calendar

case class Time(val hour: Int, val minute: Int) {
    val inMinutes:Int = hour * 60 + minute
    def -(that: Time): Int = this.inMinutes - that.inMinutes
}

Perfect. So now we can get the difference between two time stamps. Now it is time to create the class LED. This class needs to be able to store the time stamp it's created. Also, we will need to implement methods for changing its status only when the object(the LED) is not at the desired status.

case class LED() {

    var now = Calendar.getInstance()
    var hour = now.get(Calendar.HOUR)
    var minute = now.get(Calendar.MINUTE)
    private var time = new Time(hour, minute)
    private var internalStatus = 0

    override def toString = s"The LED has a status of $internalStatus. The status has not changed since ${statusTime()} minute(s) ago."

    def report { println(this) }  // uses toString

    def statusTime() = {
        now = Calendar.getInstance()
        var cHour = now.get(Calendar.HOUR)
        var cMinute = now.get(Calendar.MINUTE)
        Time(cHour, cMinute) - this.time
    }

    def turnOn() = {
        if (internalStatus == 0) {
            now = Calendar.getInstance()
            hour = now.get(Calendar.HOUR)
            minute = now.get(Calendar.MINUTE)
            internalStatus = 1
            time = Time(hour, minute)
            println("The status has changes to ON")
        } else {
            println("The LED is already ON. No change in the status!")
        }
    }

    def turnOff() = {
        if (internalStatus == 1) {
            now = Calendar.getInstance()
            hour = now.get(Calendar.HOUR)
            minute = now.get(Calendar.MINUTE)
            internalStatus = 0
            time = Time(hour, minute)
            println("The status has changes to OFF")
        } else {
            println("The LED is already OFF. No change in the status!")
        }
    }
}

Now let's make an instance of the class LED and see its behavior in REPL:

scala> var myLED = new LED //Here I new a class. We are not passing any value to it. Although a nice extention of the class LED could be to add the posibility of specifing the state of LED when creating it.
myLED: LED = LED()

scala> myLED.time
res1: Time = Time(10,33)

scala> myLED.status
res2: Int = 0

scala> myLED statusTime
res84: Int = 2

Extend a class in Scala: Subclassing

This section has to be completed, but if you are interested you may want to take a look here.

Extending an object in Scala

This section has to be completed, but if you are interested you may want to take a look here.

Conclusions

In Scala, there is a special keyword called case.

In the follow-up post, we will go through concise OO and powerful functional collections in Scala.

Have a look at here for more examples.!!


Reference


It’s easy to lie with statistics. It’s hard to tell the truth without statistics.

Andrejs Dunkels

*Cover Image Credit: DALL·E 3