Scala Beginner Series (2) : Object Oriented Scala
This series is all about the taste of Scala.
It is best suitable for all the newbies in Scala.You may also like: Scala Beginner Series (1) : Basics
In the previous part, we covered:
- Values, variables, expressions and types
- Functions and recursion
- The Unit type
This article will cover the object oriented nature of Scala language.
Classes
Scala has the same concept of a class as we have in other languages.
Classes in Scala are blueprints for creating objects. They can contain methods, values, variables, objects, traits and super-classes which are collectively called members. Fields and methods are accessed with the dot operator similar to the other languages.
Also, all fields and methods of classes are public by default, unless we restrict their visibility with the private
and protected
modifiers. We don't have to specify public
access modifier explicitly.
A minimal class definition is simply the keyword class
and an identifier. The keyword new
is used to create an instance of the class.
Constructors
Classes in Scala can take arguments — those are the constructor arguments. When we define a class, we can also define its constructor signature.
Beware that constructor arguments are not class fields . Parameters without val
or var
are private values, visible only within the class. Thus the following code will generate error:
Thus in order to promote constructor arguments to class fields, we can put a val
or var
before the argument name.
Inheritance
When a class inherits from another, it means it extends another. This lets a class inherit members from the one it extends and provides the code re-usability.
To carry out Scala inheritance, we use the keyword extends
:
In the above example of two classes, Person
class is base class or super-class and Employee
class is derived class or sub-class.
extends
clause has two effects:
- It makes
Employee
class inherit all non-private members ofPerson
class - It makes the type
Employee
a subtype of the typePerson
.
Scala also allows only single class inheritance just like Java.
Scala has the same subtype polymorphism that we have seen in other statically typed object oriented languages. In subtype polymorphism, instance of subclass can be passed to a base class.
At compile time, compiler only knows that we are calling demo()
method of Element
object. But at run time, the most derived method i.e. demo()
method of ArrayElement
is called. A derived class can, of course, override their super class methods.
Abstract Classes
Scala also has a concept of an abstract class that is similar to Java’s abstract class, which contains both abstract and non-abstract methods and cannot support multiple inheritances. They can’t be instantiated as well.
To implement Scala abstract class, we use the keyword abstract
against its declaration:
It is also mandatory for a child to implement all abstract methods of the parent class. Abstract methods of abstract class are those methods which do not contain any implementation.
Traits
Traits in Scala are similar to Java’s Interfaces. Classes and objects can extend traits, but traits cannot be instantiated and therefore have no parameters.
Traits are like partially implemented interfaces. It may contain abstract and non-abstract methods. It is possible that all methods are abstract, but it should have at least one abstract method.
Classes which extend the traits have to implement the abstract methods of the trait, but need not to implement the concrete methods of the trait.
To define trait, we use the trait
keyword:
Scala has single-class inheritance and multi-trait mixing. It is possible to extend any number of Scala traits with a class or with an abstract class.
Anonymous Classes
Scala also has the concept of anonymous classes much like Java.
We already saw how to implement parent class’s declared methods. A less formal way to provide the implementation for a parent class’s methods is with an anonymous class, a non-reusable and nameless class definition.
To define a one-time anonymous class, instantiate the parent (and potentially abstract) class and follow the class name and parameters with curly braces containing the implementation.
The result is an instance that does extend the given parent class with a one-time implementation, but can be used like an instance from a traditional class definition.
To the compiler, anonymous class looks like this:
With anonymous classes, the compiler does a lot of work behind the scenes. This allows us to abstract that complexity away from our code.
Singleton Objects
There is no idea of static
in Scala, instead we have singleton objects.
An object is a class that has exactly one instance. It is created lazily when it is referenced, like a lazy val. The methods and fields declared inside singleton object are globally accessible, we don’t need an object to access them. We can import them from anywhere in the program. Also, we can’t pass parameters to its primary constructor.
A singleton object is declared using the object
keyword:
A singleton object can extend classes and traits. It also provides an entry for program execution. Without such an object, the code compiles but produces no output.
Companion Objects
When a singleton object is named the same as a class, it is called a companion object, and the class is called companion class. The companion class-object pair has to be in a single source file. Either member of the pair can access its companion’s private members. We use a companion object for methods and values which are not specific to instances of the companion class.
I have entered :paste
mode here because I am working in the REPL
. Since companions need to be in same source file, so :paste
mode in REPL
allows companions to be defined together.
static
members in Java are modeled as ordinary members of a companion object in Scala.
The Apply Method
Scala classes as well as Scala objects, both offer a default method that we name as the apply
method. We sometimes call it an injector method. We can also invoke this method without a name. Let me show you what I mean:
Remember, apply
is just a special function that lets us call the parent object directly, like a function. It has nothing to do with object orientation, classes, or constructors in the slightest.
We can use apply in companion objects as factory methods. The idea of the factory method is to construct class instances without new
.
Case Classes
Scala case classes are like regular classes with a few key differences which we will go over. When the compiler sees the case
keyword in front of a class
, it generates code for us, with the following benefits:
- Scala case classes are immutable by default and decomposable through pattern matching.
- It does not use
new
keyword to instantiate object. This is because case classes have anapply
method by default which takes care of object construction.
- An
unapply
method is generated, which lets us to use case classes in more ways inmatch
expressions. - A default
toString
method is generated, which is helpful for debugging. equals
andhashCode
methods are generated, which let us compare objects and easily use them as keys in maps. It is used to check the value equality of all individual member fields instead of just checking the reference equality of the objects.
- We can create a shallow copy of an instance of a case class simply by using the
copy
method. We can also change the constructor arguments.
- All the parameters listed in the case class are public and
val
by default. It is possible to usevar
in case classes but this is discouraged.
Case objects
A case object
is like an object
, but just like a case class has more features than a regular class, a case object has more features than a regular object. Its features include:
- It’s serializable
- It has a default
hashCode
implementation - It has an improved
toString
implementation
The biggest advantage of case classes and case objects is that they support pattern matching. Pattern matching is a major feature of functional programming languages, and Scala’s case classes and objects provide a simple way to implement pattern matching in match expressions and other areas.
You may also like: Pattern Match Anything in Scala
Similar articles -
You can also checkout my other articles on Scala Beginner Series —