Scala is a functional programming language for the Java Virtual Machine. But, what is exactly functional programming? It's a programming model where we use only pure functions. This means that this functions do not have any kind of side effects.
Now the question is: What's a side effect? They are actions like modifying variables, data structures or fields on objects; throwing exceptions and halting with errors; reading or writing to files, including the console, or drawing on the screen.
But I need my program to do all of those things, you may think. Indeed. You can do all this with a functional programming language, but the approach here is to limit side effects to the minimum, not have them scattered accross the codebase.
The other piece we mentioned were the pure functions. These are functions where the output depends solely on the inputs. This means that, no matter how many times we provide a certain input, the output will be the same. Functions do not hold any kind of state at all, because this would be a side effect, and a pure function doesn't rely on them.
Let's learn the Scala syntax with a simple example:
object MyModule {
def abs(n: Int): Int =
if (n < 0) -n
else n
private def formatAbs(x: Int) = {
val msg = "The absolute value of %d is %d";
msg.format(x, abs(x))
}
def main(args: Array[String]): Unit =
println(formatAbs(-42))
}
The previous example should be stored in a file called MyModule.scala. Then we can compile it to Java bytecode using the scalac compiler:
$ scalac MyModule.scala
This will generate files with .class extension, which can be executed with the scala command line tool:
$ scala MyModule
The absolute value of -42 is 42.
Very Java like, so far. However, Scala has an interpreter as well, which can compile the code on the fly and then run it. To invoke it, simply type:
$ scala MyModule.scala
The absolute value of -42 is 42.
You don't even need to write your Scala code into a file. Just execute the scala program without arguments, and it'll wait for you to start typing some Scala and it will evaluate it on the go.
Of course there are plugins available for the most usual IDEs, and if you are using Scala in a bigger project, the sbt tool is the answer for dependency management and project lifecycle.
The idea behind this is a new one: functions are values. This means you can do with them anything you would do with any other value: assign it to a variable, store it in some data structure, and pass it as argument to a function. A function which accepts another function as an argument is called a high order function.
Imagine you want to find out which elements of a list meet some condition, and get these elements in another list. We'll call this function filter, and we can define it in Scala as follows:
def filter(l: List[Int], f: (Int) => Boolean): List[Int] = l match {
case x :: xs => if (f(x)) x :: map(xs, f) else map(xs, f)
case _ => Nil
}
Several things going on here. First of all, with the match keyword, we apply a concept called pattern matching. This is a very common and useful concept in Functional Programming. It will basically test if the given expression, the list in this case, matches a certain pattern. As soon as a match is found, it Scala will stop comparing, and will execute the action related to that case. We can think of it as some sort of "advanced" switch statement.
Let's take a look at the first case expression, x :: xs. This is actually one of the ways of building lists in Scala. x represents the first element of the list, also called head. xs is the tail of the list, where all the rest of elements live, and it is a list as well. So, if the list follows this pattern (it has a first element followed by another list, which could be empty or not), filter will return the head of the current list, provided it meets the condition, and then will apply itself recursively to the tail of the list.
The second case expression just means that, if the list l matches anything else, Nil will be returned. The underscore is used to represent something which can be found in the expression, but we are not interested in.
We can now separately define a function which takes an integer and returns a boolean, but instead of that we'll just define this function at the same time as we call filter.
$ map(List(1, 2, 3, 4), n => n > 2)
res0: List[Int] = List(3, 4)
This kind of function definition is called Lambda. It is very handy to declare functions this way for increased readability, and will save us some lines of code as well.
These are the very tiny bits of Scala, we barely scratched the surface. The learning path is long and has to be taken little by little. Just remember, don't use Scala just as a better Java because it is much more than that. You can start writing Scala code and integrate it with some existing Java project straight away, and some of the features in Scala, such as streams or lambdas, are also part of other languages, like Java 8. What I am trying to say with this is that, even if you are not going to develop in Scala, or not even in a functional language, you can always apply some of this concepts and make your software development easier.
Bogdan Utanu
Tags: scala
June 23rd 2016