Welcome back! In the last part of this series we took a quick look at how you declare immutable variables, then looked at the “everything is an object” features of Scala, and now we are going to jump back into some simple variable declarations, but this time we are going to look at creating mutable variables.
Mutable Variables
You might be wondering why we didn’t just go ahead and jump straight into mutable variables after discussing immutable variables, and the reason is that I wanted to give you a bit of advice before introducing them. Basically, Scala takes the stance that most things should be immutable and the developer should really only fall back to mutable objects when it makes sense from a complexity or performance standpoint.
Here is how we would declare a mutable integer in Scala:
var x = 1
Easy, huh? All we have to do is just replace “val” with “var”. But remember, using var just makes the reference mutable, it doesn’t change the object underneath. So basically, if we had a string declared like this:
var myString = "hello "
Then if we concatenated like this:
var myString2 = myString + "Scala"
Then the references would not be equal. The reason is that strings in Scala, just like in C#, are immutable structures. Just because we can now change the references to these variables, doesn’t mean that the strings are now immutable themselves. It is now valid for us to reassign one of the above strings like this:
myString = "something else"
And now the value has changed. The Scala REPL will print the values out to the screen, but if you want to print something explicitly, you can just use the println method:
println(myString)
Now that we know how to declare simple variables in Scala, let’s take a quick look at a few control and looping structures.
The “if” Statement
First we are going to take a look is the “if” statement. It is exactly the same as the “if” statement that you have grown to love, with just a few minor differences. First, we can use the if statement just as we could expect:
val name = "justin" if (name == "justin"){ println("It is justin!") } else { println("It isn't justin!") }
In fact, this “if” statement looks exactly as it would in C#. In Scala, just like in C# the curly braces are optional when we are only dealing with single lines in the if and else blocks:
if (name == "justin") println("it is justin!") else println("it is not justin!")
So far we haven’t seen any differences between this and the C# “if” statement. The big difference in the Scala version is that I can rewrite my if statement to look like this:
if (name == "justin") "it is justin!" else "it is not justin!"
Huh? To a C# or Java developer this might look a bit odd. Why would we want to do this? The answer lies in the fact that the “if” statement in Scala can have a result value. So while the statement above doesn’t make much sense, if we assign that value to a variable then it starts to look more useful:
val result = if (name == "justin") "it is justin!" else "it is not justin!"
And when you realize that you can now do simple one liners like this:
val result = if (name == "justin") "it is justin!" else "it is not justin!"
We no longer need special language constructs like the C# ternary operator to perform this operation. This is nice, but for some reason I still like the look of my old ternary operator better! Oh well. Reducing the surface area of the language by reusing language constructs is something that should probably take precedence here.
The “for” Comprehension
The next control structure that we are going to glance at is the “for” comprehension. This one may be a bit of a surprise for C# developers because it is not all like the “for” loop that they are used to. In fact, it is closer to the “foreach” loop that you have used so often. As with most of the features in Scala, it will start off looking familiar, then it will turn around and surprise you at the end. We are going to look at the “for” comprehension in its familiar form, then we will delve into its more surprising aspects.
But first, in order for us to use a loop we need something to loop over. Without getting into Scala sequences I am just going to introduce you quickly to ranges. A range is just a sequences of numbers from one point to the other. In C# we are able to iterate over an integer range by doing this:
foreach (int num in Enumerable.Range(1, 10)) { Console.WriteLine(num); }
Useful, but not as succinct as we would like it. And in fact, the code is a little deceptive because it is not a range going from 1 to 10, but rather a range starting at 1 and returning 10 numbers. A subtle, but obviously important, difference. With Scala the integer object (RichInt) has a “to” method. Since we already saw that in Scala a method with a single parameter doesn’t need to have a “.” or parentheses when accessing it, we can create a range in Scala like this:
val range = 1 to 10
Very cool indeed. Ruby developers will feel right at home with this syntax. Now we need to iterate over this range with the Scala “for” loop. This can be accomplished like this:
for (num <- 1 to 10) println(num)
In place of the word “in” from our C# foreach loop we have a “<-“. In Scala this is known as a “generator”. It is just creating a new “val” for each item in our sequence and passing that into the body of the loop. The above code will do exactly as we expect, and it will print out the numbers 1 through 10 to the console window. This looks very familiar at this point, but now let’s look at some of the “for” magic I was talking about.
Filtering Lists
Let’s pretend now that we want to take the the numbers from 1 to 100 and print out only the numbers that were even divisors of 6. We would end up with code that looks like this:
foreach (int num in Enumerable.Range(1, 100)) { if (num % 6 == 0) Console.WriteLine(num); }
Okay, now let’s say we wanted to print out only the numbers that were even divisors of 6 and 4. We could have code that looks like this:
foreach (int num in Enumerable.Range(1, 100)) { if (num % 6 == 0) if (num % 4 == 0) Console.WriteLine(num); }
In Scala, the “for” comprehension allows us to do much of this filtering within the for loop itself. First, we can start using curly braces instead of parentheses to surround the generator. We can then produce the above C# code like this:
for { num <- 1 to 100 if num % 6 == 0 if num % 4 == 0 } println(num)
Hmmm. It is pretty interesting looking code. And when you think about it, it is doing something very similar that C# does with Linq. We could leverage Linq to write the above code like this:
Enumerable.Range(1, 100) .Where(n => n % 6 == 0) .Where(n => n % 4 == 0) .ForEach(Console.WriteLine);
Looks very similar indeed. And no, the “ForEach” method is not a built in Linq method, but it is one that I add to many projects I work on. As you can see, we can add filters to “for” comprehensions in Scala which allows us to control which items in the sequence get passed to the body of the loop.
Iterating Sublists
Another interesting thing that Scala “for” comprehensions allow us to do is to do iteration over subsequences. So let’s say we have an array of arrays like this in C#:
var nums = new [] { new [] {1, 2, 3}, new [] {4, 5, 6}, new [] {7, 8, 9} };
If we want to iterate over all of the items in these lists then we could either next foreach loops like this:
foreach (var subList in nums) { foreach (var num in subList) { Console.WriteLine(num); } }
Or we could use the SelectMany Linq method like this:
nums .SelectMany(subList => subList) .ForEach(Console.WriteLine);
If we wanted, we could also use the query syntax like this:
(from subList in nums from num in subList select num).ForEach(Console.WriteLine);
With Scala the “for” comprehension makes this a bit easier and allows us to perform this operation at an arbitrary depth:
val nums = Array( Array(1,2,3), Array(4,5,6), Array(7,8,9) ) for { subList <- nums num <- subList } println(num)
You can see here that we are getting each sub-list from the list and then pulling each number out of each sub list. The code will write the number 1 through 9 out to the console. As if the “for” comprehension wasn’t doing enough already, there is one more trick up its sleeve.
Creating Lists from Lists
Let’s take a look at this code again:
foreach (var subList in nums) { foreach (var num in subList) { Console.WriteLine(num); } }
This is the nested “foreach” loops where we are looping through sub-lists. What do we do here if we wanted to create a resulting list? We could use the C# “yield” keyword like this:
public static IEnumerable<int> Iterate(int[][] list) { foreach (var subList in list) { foreach (var num in subList) { yield return num; } } }
Notice that we had to create a method to do this. The C# yield keyword doesn’t work unless it is wrapped in a method that returns an IEnumerable. In this case though, this method is useless since we would just use the result of “SelectMany”.
Scala provides us with a very similar ability using what is referred to as “sequence comprehensions”. This functionality uses the “for comprehension” with the added “yield” keyword. The iteration on the sub-lists from above would look like this:
val result = for { subList <- nums num <- subList } yield num
With Scala it is easy to simply return the result of the “for” with “yield” to a variable which will be of the same list type as that which is being iterated over. As you can see, the “for comprehension” in Scala has quite a bit of power. It can be a bit complicated but it is well worth it to learn the power that it affords you.
It is also certainly worth noting though that all of the collection types that Scala provides implement the Seq trait (we will talk about traits in the future) which provides the ability to perform many selecting, sorting, filtering operations on the lists directly by calling methods rather than using the “for comprehension”. This way you get that same functional style method chaining that you love so much with Linq.
Summary
Well, this post got a bit long and out of hand, but the “for comprehension” just has so much going on! I hope that you learned something, and I hope that you are starting to see a few of the ways in which the designers of Scala approached some of the same problems we have in C#, but in a very different way. When we come back next time, we are going to take a look at methods in Scala and how we can define and execute them. Once we get that out of the way, we will look at some of the operations that we have performed on lists above but instead using the methods on the list types themselves. See you next time!
Loved the article? Hated it? Didn’t even read it?
We’d love to hear from you.
Seems very nice… With these examples I would say Scala seems to be more powerful than C# but maybe not as powerful as F-Sharp.
I tried to make equal codes in F#.
Here is filtering:
[1..100] |> List.filter (fun x -> x%6 = 0) |> List.filter (fun x -> x%4 = 0)
And this is list iteration:
let nums = [[1..3];[4..6];[7..9]]
nums |> List.iter (fun i -> i |> List.iter (fun j -> printfn "%d" j))
Or even simpler solution with flattening the list of lists:
let nums = [[1..3];[4..6];[7..9]]
List.concat nums |> List.iter (fun i->printfn "%d" i)