Scala Tutorials Part #5 - Classes
Originally Posted On : 17 Nov 2016 Last Updated : 18 Oct 2017
This is part 5 of the scala tutorial series. Check here for the full series.
- Access and visibility
- Class parameters and Class fields
- Promoting class parameters
- Direct member access
- Immutable objects and Mutable objects
- When to use Getters and Setters
- Scala style Getters and Setters
- Auxiliary constructors
- Default constructor values
- Named arguments
- Abstract classes
- The Override keyword
- When to use abstract classes
The concept of a class in scala is very similar to their counterpart in java. But there are lot of differences in the functionality they provide.
To start off, let’s take a simple example.
We have two variables
age with getters and setters which can be accessed as follows.
Previous example had the default access modifier. Let’s look at other modifiers in detail.
To recap, java has four access modifiers.
Java access levels
A similar representation can be drawn for scala.
* Top level
private members can be accessed from inside a package
It is more or less similar to java’s access modifiers, except that there are only three levels. There is no equivalent of java’s default access, and the default in scala is equal to java’s public.
This should be enough to get going, but if you are interested in taking a more deeper look, scala access modifiers is a good read.
The official documentation can also be referred.
You would find that, the scala access levels are slightly better in contrast to java.
Next obvious thing to understand in a class would be constructors. Unlike java, there are some unique ways to create constructors.
The class implementation is similar to the original one, except that there are no setters and only getters.
They can be consumed as below.
Method style parameters are given during class definition to indicate constructors.
Once a constructor is declared, we cannot create a class without providing the default parameters as specified in the constructor.
We cannot call the variables directly as they resort to
private val by default and as per the access levels defined above, it would throw an error.
It is important to understand that for a class, there are two components i.e class parameters and class fields.
Class parameters are one which you mention in declaration i.e the primary constructor.
Class field are regular member variables.
The above example had getters, without those it would be impossible for another class to access the variables of that particular class.
If we take a closer look, the actual reason is more subtle than just private, the parameters have scope only to the constructor and do not live beyond that. This is very similar to accessing a variable that is declared inside a loop. These are class parameters and live only inside the scope of the constructor.
Class fields on the other hand can be accessed (based on their access level) outside the class.
This distinction is important and it forms the basis of the following discussions.
The process of promoting class parameters is nothing but changing their scope for usage beyond the constructor.
This can be done in two ways. Either by affixing
var before the variables in the constructor parameters.
Even though the classes do not have a body, instances can still be created and consumed.
Changing the parameters to val/var enables us to directly access the class variables, without a getter/setter.
The above example with either val/var can be consumed as below.
We can access the variables directly since it is the default access level. In fact, val/var do not have anything to do with access.
Designing things like this is a bad idea, but it is something that can be done.
This gives rise to two ways in which a class can be designed i.e mutable/immutable.
With val, we can have immutable objects.
We can declare the variables as immutable in class constructors.
Once the values are declared, it cannot be re-assigned again, this is the default behaviour of val as explored in the first part.
Scala has something called
case classes which are specifically built for handling situations like immutable classes along with several other neat features.
We will be exploring cases classes in a future tutorial.
We can then declare an instance and change the name directly.
There are two key decisions to be made when designing a class.
- Whether it should be mutable/immutable (Read objects should be immutable)
- Using getters/setters vs direct variable access.
For the first point, it is basically trade offs. The linked article summarizes the advantages of immutable objects.
The second point is something to ponder over.
Traditional wisdom in java on when to use getters and setters still apply.
A simple example is to do more than just setting values to the variable, we can do several other things such as checking access, logging etc.,
But the scala style guide says a different story.
What is being advised is that the users of the class need not have knowledge on whether a method/class member is being accessed. They can simply choose to change/access it with the variable name itself. This greatly simplifies code and it looks much cleaner.
The next section describes on how to create such a getter/setter with a somewhat obscure syntax.
Scala has a different way of creating getters/setters although the java style is still supported as we saw in the first example.
Lets take the below class.
This can be consumed as below.
age is actually a method inside the class Person, however the user can access this as if it was a variable.
The syntax might look bizarre, but understanding where they fit in will give a more clear picture. Lets take it apart piece by piece.
age is actually
_age behind the scenes. The getter is pretty clear, just return the
The setter is little more confusing. First the method name is
def age_=, the underscore is a special character which enables a space in calling the method.
This enables us to call the method like
Notice that the method name, underscore and the equal sign should be together without any space.
Everything else should make sense already i.e it takes in a parameter
value and assigns it to the
This definition should be enough to get your head around it, but the underscore character has more to it and there is something called the uniform access principle. We will explore that in later dedicated tutorial.
Scala plugin in Intellij can do all the code generation for you.
Getters and setters in general are viewed as second class citizens since scala encourages immutable objects.
In a real world scenario we often need to have two or three constructors with different parameters.
To do this we have a special style of constructor creation called auxiliary constructors.
The comments on the code pretty much sums up the idea. An important thing to note is that an auxiliary constructor is not an actual constructor, but acts as a wrapper to the existing constructor.
When we want to add a parameter to the above person class, say a phone number, then we add it to the primary constructor i.e the class parameters.
Please note that the all of the auxiliary constructors have to now include the phone as a parameter. This might seem as an overhead, but it is actually good design.
Auxiliary constructors are good for implementing polymorphic behaviour, i.e different constructors can exhibit different flows in the class execution/functionality.
A most common bad practice is to use these to implement default variable values.
Like methods, we can provide the default values during constructor declaration itself.
We can then consumer this class without declaring value to one or even all of them.
Listed example will work correctly and would print the default values Unnamed,-1,No number.
This is a pretty handy way of declaring pre-defined class values.
We can create classes with only specific variables as user defined and leaving the rest to the class defaults.
If we want to give only the
name and leave the rest of the variables as defaults then,
Abstract classes in scala are similar to java, but they are superseded by a concept called
traits. We will explore traits in a later tutorial.
Below is a simple example of an abstract class.
The comments give a good idea of what the methods do. The
abstract keyword is not necessary, when the method body is not defined it is taken to be as a abstract method.
If we extend this to another class, we need to implement the three methods
We may choose to override/not override the
getName method since it is already implemented.
In Java when we need to override a method from a parent class we need to do anything special. For clarity we can use the
Scala has an
override keyword which is mandatory in case of overriding a concrete method from a parent class.
This promotes better type safety and accidental overriding.
We can add a
override keyword in front of the method to work as expected.
As I said before, abstract classes were superseded by
traits, so in what situation we need to use Abstract classes ?
This requires more knowledge of traits, but we will briefly touch upon two situations.
When we want a base class with constructor arguments
We will see in further tutorials why traits do not allow this.
When we want to use the class from Java code
Since traits are something specific to scala, abstract classes are better in terms of compatibility.
With this, I would like to bring an end to this tutorial. The next in this series would be understanding case classes, traits and why they are really cool.