Learning Scala in 5 parts: Part 4

Types

Today we are going to learn about types. This is something we only barely touched so far. More specifically, all functions that we defined so far that take arguments have had the types specified for the respective arguments. Furthermore, every class you have defined in the previous parts were types themselves. You can more or less think of types as being “what a class describes“. The only thing keeping it from being this simple is the fact that there are different types of classes and even some types that aren’t really classes.

In Scala you don’t always have to present the types in your program. A good example is the declaration of a variable:

This is equivalent to:

But I guess you can easily tell that i is going to be an integer. After all, we are assigning an integer right away, right? The same thing holds for functions. You don’t always have to specify the return type of a function because it can be quite obvious. Similar to the above, consider:

Which is equivalent to:

Again, the type should be quite obvious from the context. There are situations where you must specify the types. When you make a recursive function (a function that calls itself), the type must be specified. This is because the scala compiler can’t infer the type of a recursive function on its own.

To show where and how you can describe the types, here is the program from the last part with all types specified:

You should take your time to verify that the above is correct. Also, think about when you would put the types yourself. When is it beneficial to the reader with explicit types? When is it not?

Polymorphism

Now that’s a big word, but don’t sweat it, it’s quite easy to understand.
The type system in scala is very powerful. Basically, using types strictly is a way to enforce better code and helps the programmer to catch errors before running the program, namely when compiling. Since variables and functions can only have one type, it is essential to allow generalization of types.

A typical workflow for creating general types is to first create an abstract class. Abstract classes are classes that you cannot use directly to create new objects (aka. instantiation). Since you can’t instantiate objects from abstract classes they can also have both functions and variables that are undefined. Why would you want functions that are undefined? To force subclasses to define them! I guess it’s time for an example:

Human is the abstract class and both Man and Woman are classes that extend Human. We say that Man and Woman are subclasses of Human, and Human is the super class of both Man and Woman.
Running this sexist piece of code yields the following result:

Notice, if you try to create a Human you would get the following error:

What’s the fun about the code so far? Polymorphism! Polymorphism simply means that a variable can contain different types of values at different times in the program. We didn’t really utilize it much, but let’s see what we could use it for:

Now we have a function that takes a human argument h. The function never knows whether the human is male or female, but that’s not necessary since we know that humans can speak. Because we can call speak on any human, we can get different result when we get different subtypes as input.
The program runs as follows:

Rule of thumb with polymorphism: Always make your program work on a ‘need to know basis’, such that functions take/return the most general types possible.

Imagine if you had several different list-like types in a program (this is very much the case in Scala’s standard library), wouldn’t it be nice to be able to use any kind of list in your program without changing all the argument and return types? Yes it would! Examples of functions that are generally present on lists are head,tail,last,toString,concatenation,map,filter,reduce. The list/sequence types in Scala’s standard library are extremely advanced and use polymorphism in it’s most extreme form. If you are feeling particularly masochistic you can have a look Seq in the current scala standard library.

Traits

A trait is an example of something which is not really a class, neither an abstract class. Google was quite helpful in giving me this definition:

"a characteristic feature or quality distinguishing a particular person or thing"

Well, humans can have traits.

This time humans have a sentence that they like to say. Also, they can of course speak, but only the one sentence they know! Humans can be loud, so let’s define loud behaviour:

We define traits with the keyword trait, and by extending Human we say that this trait can only belong to Humans. The trait simply maps the toUpper function on the string making it all uppercase and then adds a few exclamation marks in the end. Override is a mandatory keyword when we define functions that are already defined in super-classes or super-traits (the classes/traits that we are extending). Since Human contains a function called speak we have to override it. This also means that this is the function that will be called instead when we use this trait.

Another human trait is Obnoxiousness. To my knowledge, obnoxious people don’t ask politely and they burp. Let’s code that:

Okay, so as we used override on a function before, here we also use it on the sentence value. It works the same way. Now, in the new speak function we have the following code:

This means that even though we override the function, we can still call the original functions from the class we are extending. That’s all good, but how do we use it? Try this simple program:

First, we create a human variable. This time Human isn’t abstract so it’s not a problem to create one. Also, it can speak. (notice, you don’t have to put parenthesis() behind function calls like speak. Maybe you should!).
After this we create a new Human, but we give it a trait with the with keywoard. This means that the created object will gain the methods and variables in the trait. We speak with the new object and repeat with the Obnixious trait.

Running it gives the following output:

Okay, that looks like the expected output. But how is this different than extending? Because you can do this:

First, we make a human and then we add Loudness and Obnoxiousness to it. You can’t extend multiple classes, so this is a powerful alternative. Running it yields:

Aha, it worked the way you would think. First we added loudness. So we expect the sentence to be capitalized. Then we added obnoxiousness, so we expect it to burp and to use an impolite sentence, which is exactly what we got. Notice how we got a unique result by combining the traits.

One thing is missing. What if we mix in the opposite order:

Now what do you think will happen? We still mix the two traits, so we should expect both traits to alter the behaviour of speak. However, since we mix in loudness last, we will be calling the speak function from Loudness instead of the one from Obnixiousness, but since Obnoxious already changed the sentence we know, we should still be yelling the new sentence. That means that there will be no burping because this is simply a side effect of the obnoxious speak function. Let’s see what really happens:

Yay, it worked like we expected. One might not want to type with all the time when creating objects, so an idea is to combine this into a real class:

This of course yields the same result:

Yeah…the only good thing about Ben Stiller is that he is not Nicolas Cage.

Conclusion

There is a lot to take in from this part, but keep in mind that being good with types is a great quality as a programmer. Using the type system effectively will allow you to maintain the overview of a large software project while achieving reusable and readable code.
I have been using this

a lot through this part. You should consider if it is a good idea to call functions without using parenthesis. Can you tell wether speak is a function or a variable in this code? A good idea is to skim through the Scala Style Guide to learn a bit about best practise. An IDE (integrated development environment) can help you format your code while writing. I have had the most success with the Eclipse Scala IDE, however, don’t go on this adventure unless you are ready to spend some time getting to know a big piece of software.

If you followed the tutorial so far and took your time to understand as much as possible, it is time to relax with a big pot of coffee. In the next part I will be solving some more mathematical problems in Scala. The technical introduction to Scala more or less ends here, but this doesn’t mean there isn’t loads of things we haven’t touched. Note that you should still be able to create all kinds of applications with the knowledge you have gained already.
There are tons of educational webpage/blogs out there, and I really recommend going to the official scala webpage and browsing through the docs. Of course I also recommend following part 5 when it arrives 🙂

Part 5

CategoriesUncategorized

Leave a Reply

Your email address will not be published. Required fields are marked *