Programming  /  Scala August 19, 2010

Learning Scala part four – Classes and Constructors

In the previous part of the Learning Scala series we looked at the different ways by which we can execute Scala code. In doing so we looked at how to print out Hello world in three ways, using the interactive interpreter, executing a script and by compiling and executing a console application. In order to build a console application we took a quick look at the object construct and also at how methods are defined in Scala. In this part we’ll begin to look at classes and constructors in particular.

Declaring and instantiating classes

In the previous post we created a script, hello.scala, which printed “Hello world” to the console when it was run using “scala hello.scala”.

// Inside hello.scala
println("Hello world!")

Let’s rewrite that to use a class that does the same thing.

class Greeter {
    def SayHi() = println("Hello world!")
}

val greeter = new Greeter()
greeter.SayHi()

In the above script we first declare a class named Greeter with a single method, SayHi. We then create a new variable named greeter whose SayHi method we finally invoke.

Considering that we looked at how methods are defined in the previous part there’s not really anything strange or funky in the class definition. The same goes for the instantiation of the class. Just like in C# and Java we create a new instance using the new keyword. We assign it to a variable which we create using the val keyword. That’s something new though. In Scala we create variables either using the val keyword or the var keyword. Using val we get a read-only variable that’s immutable. In other words, once it’s value is assigned it can’t change. If we on the other hand create a variable using the var keyword we get a mutable variable whose value we can later change. In this case an immutable variable is fine, but if we were to reassign the variable later on, like this…

class Greeter {
    def SayHi() = println("Hello world!")
}

val greeter = new Greeter()
greeter.SayHi()
greeter = new Greeter()

…then we’d get a compilation error:

c:\learningscala\Classes and methods>scala helloWithClass.scala
c:\learningscala\Classes and methods\helloWithClass.scala:7: error: reassignment
to val
greeter = new Greeter()
        ^
one error found

If we’d change the greeter variable to instead be a var, like in the snippet below, the code would compile and run just fine.

class Greeter {
    def SayHi() = println("Hello world!")
}

var greeter = new Greeter()
greeter.SayHi()
greeter = new Greeter()

Constructors in Scala

Let’s say that we want to provide the message that the Greeter class writes to the console upon instantiation. Then we’d need a constructor. Constructors are a bit different in Scala than in C# or Java. In Scala the primary constructor is the class’ body and it’s parameter list comes right after the class name. So, to provide the message that Greeter will print using a constructor we can modify our code to look like this:

class Greeter(message: String) {
    def SayHi() = println(message)
}

val greeter = new Greeter("Hello world!")
greeter.SayHi()

To a C# or Java programmer (or at least to me) it looks like the message variable is a method parameter and it certainly is a parameter to the constructor. But, as proved by the fact that we can use it in the SayHi method, it is also a field in the class. That’s actually not entirely true though. The parameter isn’t a field, but the compiler will automatically create a field for us and take core of setting it’s value. Anyhow, the field is by default a val (immutable) and it’s access is public. That means that the above class definition in Scala is close to functionally equivalent to the below class definition in C#.

public class Greeter
{
    public readonly string message;

    public Greeter(string message)
    {
        this.message = message;
    }

    public void SayHi()
    {
        Console.WriteLine(message);
    }
}

How strange! But also a bit intriguing right? After all we accomplished what in C# took six lines (not counting lines with just curly braces) in just two lines in Scala. From a Java or C# perspective one might be a bit suspicious of that the message field was made public by default though. We’ll look into why that is, and why it’s sensible that it is that way, later.

As I mentioned before the class’ body is the primary constructor so if we wanted to perform some operations when an instance is created we would write that code directly in the class’ body.

class Greeter(message: String) {
    println("A greeter is being instantiated")
    
    def SayHi() = println(message)
}

val greeter = new Greeter("Hello world!")
greeter.SayHi()

In the above example we added a call to println to print a message when a Greeter is being instantiated. Running this script produces the following output:

A greeter is being instantiated
Hello world!

If we would turn the message field into a var instead of a val we could also modify it when the class is instantiated.

class Greeter(var message: String) {
    println("A greeter is being instantiated")
    
    message = "I was asked to say " + message
    
    def SayHi() = println(message)
}

val greeter = new Greeter("Hello world!")
greeter.SayHi()

The above script produces this output:

A greeter is being instantiated
I was asked to say Hello world!

Auxiliary constructors

While the class’ body is the primary constructor we are free to add as many additional auxiliary constructors as we want. There is a constraint for these though. An auxiliary constructor must, on the first line of it’s body, call either another auxiliary constructor that has been declared before before it or the primary constructor. To obey this rule each auxiliary constructor will, either directly or indirectly end up invoking the primary constructor.

Auxiliary constructors are created by defining methods named “this”. To illustrate the use of an auxiliary constructor let’s modify our previous example to include a second message in the primary constructor that the SayHi method will append to the first message when printing it out.

class Greeter(message: String, secondaryMessage: String) {
    def SayHi() = println(message + secondaryMessage)
}

val greeter = new Greeter(
    "Hello world!", 
    " I'm a bit more chatty than my predecessors.")
greeter.SayHi()

Running this script produces the following output:

Hello world! I'm a bit more chatty than my predecessors.

Now, suppose we would want to add another constructor that only requires the first message. To do so we add a method named “this” that accepts a single parameter. To satisfy the previously mentioned rules for auxiliary constructors it must call the primary constructor and thereby supply values for each of it’s parameters. In other words, in Scala the primary constructor defines all of the values that is required to create an instance of the class and, in contrast with C# and Java, all other constructors must also supply these values even if they don’t themselves require them as parameters.

Our script modified to include, and use, the auxiliary constructor looks like this:

class Greeter(message: String, secondaryMessage: String) {
    def this(message: String) = this(message, "")
    
    def SayHi() = println(message + secondaryMessage)
}

val greeter = new Greeter("Hello world!")
greeter.SayHi()

Abstract classes

Abstract classes works just like in Java or C# and we declare them using the abstract keyword. To illustrate, let’s modify our previous example so that the Greeter class is abstract, having a concrete implementation of the SayHi method that prints the value of an abstract field. We then create a class, SwedishGreeter, that extends Greeter and defines the message to say “Hej världen!” which means hello world in Swedish.

abstract class Greeter {
    val message: String
    def SayHi() = println(message)
}

class SwedishGreeter extends Greeter{
    message = "Hej världen!"
}

val greeter = new SwedishGreeter()
greeter.SayHi()

Recap and a look at the next part

In this post we took a look at how we can declare classes in Scala which is very similar to C# and Java. We also looked at constructors which works a bit differently in Scala than in Java and C#. In the next part we’ll look closer at methods which have some interesting characteristics in Scala.

About this post and the Learning Scala series

This post is a part of a series of posts in which I describe my experiences while trying to learn Scala. I try to do it in the form of a tutorial as I find doing so is an excellent way of consolidating knowledge and hopefully I can also help others. However, keep in mind that I’m in no way an expert on Scala. This is just a way to document what I’ve learned so far and there might be some things that I’ve misunderstood. If you’ve found such a thing and would like to help me correct that misunderstanding, or if you would like to leave any other kind of feedback don’t hesitate to leave a comment!

You can find links to all posts in this series at the bottom of the first post.

PS. For updates about new posts, sites I find useful and the occasional rant you can follow me on Twitter. You are also most welcome to subscribe to the RSS-feed.

Joel Abrahamsson

Joel Abrahamsson

I'm a passionate web developer and systems architect living in Stockholm, Sweden. I work as CTO for a large media site and enjoy developing with all technologies, especially .NET, Node.js, and ElasticSearch. Read more

Comments

comments powered by Disqus

More about Scala