Sage-Code Laboratory
index<--

Scala Classes

A Class is a composite data type. Some classes belong to Scala system but you can also create new classes. From OOP we know a class is a blueprint for making objects. Not all classes are used this way. Some classes are used to encapsulate methods or functions and not for instantiation.

If you have understood the previous paragraph, you are ready to learn about Scala classes. Otherwise we recommand you read programming paradigms article from Software Engineering tutorial, or just look at this picture to grasp the concept and move forward. You will catch up later.

class

Class Anatomy

Class Constructor

In Scala a class is defined by its constructor. So when you create a class you actually define a default constructor. In this example we create a class called "Person" with 3 fields, using a single line of code:

// define a simple class
class Person(val firstName: String, val lastName: String, var age: Int = 0)

//using the simple class to create two instances
val p1 = new Person("Bill", "Gates", 65)
val p2 = new Person("Martin", "Odersky", 62)
val p2 = new Person("Steve", "Jobs")

//accessing fields of opjects
println(p1.firstName) //Bill
println(p1.lastName)  //Gates`
println(p1.age)       //65

//modify a property (next year)
p1.age = 66     // mutate field value
println(p1.age) // 66

Notes:

News: keyword "new" is used in Scala 2 but is about to be deprecated in Scala 3. For now, this tutorial apply Scala 2 conventions. Our examples run on repl.it website where only verion 2 is available. When this will change we will update our tutorial.

Class with Methods

In the previous class, we can see property "age" is mutable. That means we can change person age. But the age can move only forward, a person can not get younger. So we need some logic to increment a person's age.

/* class with methods */
object Main {

  class Person(val firstName: String, val lastName: String){
    private var age: Int = 0
    // define 3 methods
    def setAge(age:Int) = this.age = age
    def getAge() = age
    def incAge() = age += 1
  }

  def main(args: Array[String]): Unit = {
    val p1 = new Person("Elucian","Moise")
    p1.setAge(55)
    println("age=" + p1.getAge())
    p1.incAge()
    println("age=" + p1.getAge())
  }
}

Notes:

Homework:

Open this example on-line, run it then create a new person "p2" and set-up person's age. click here to open

Auxiliary Constructors

A class can have more than one constructor. Each constructor can have different parameters. The constructor is a method having name: "this". Each auxiliary constructor must call the default constructor explicit.

/* demo auxiliary constructor */
object Main {

  class Person(val firstName: String, val lastName: String){
    private var age: Int = 0
    // define 3 methods
    def setAge(age:Int) = this.age = age
    def getAge() = age
    def incAge() = age += 1
    // auxiliary constructor
    def this(firstName: String) {
      this(firstName,"") //call default constructor
      this.age = 1       //you can not be famost until your birthday
    }
  }

  def main(args: Array[String]): Unit = {
    val p1 = new Person("Madona")
    p1.setAge(62)
    println("firstName=" + p1.firstName)
    println("lastName=" + p1.lastName)
    println("age=" + p1.getAge())
  }
}
Info: In practice, you can use default values for parameters, therefore making auxiliary constructors is not very frequent. It is available for having more complex initialization logic.

Inheritance

As expected from any OOP language, Scala has ability to extend a class. When it does, it create a new "specialization" class of an existing class. The new class is called also "subclass" and inherite all fields and methods of the "superclass".

Example:

In next example, look for keyword "extend" this define a subclass. In next example, ColorPoint is a subclass of Point. It has an additional attribute and one additional method: equal(). The old method move() is overwriden.

/* subclassing demo */
object Main {
  class Point(xc: Int, yc: Int) {
    val x: Int = xc
    val y: Int = yc
    def move(dx: Int, dy: Int): Point =
      new Point(x + dx, y + dy)
  }
  //define a subclass of superclass Point
  class ColorPoint(u: Int, v: Int, c: String="black") extends Point(u, v)
  {
    val color: String = c
    def equal(pt: ColorPoint): Boolean =
      (pt.x == x) && (pt.y == y) && (pt.color == color)
    override def move(dx: Int, dy: Int): ColorPoint =
      new ColorPoint(x + dy, y + dy, color)
  }
  def main(args: Array[String]): Unit = {
    val cp  = new ColorPoint(1,1,"red")
    val cp1 = cp.move(1,1)
    val cp2 = cp.move(1,1)
    println(s"(${cp1.x}, ${cp1.y},${cp1.color})")
    println(s"cp1==cp2 "+cp1.equal(cp2))
  }
}

Notes:

Singleton Objects

Scala is more object-oriented than Java because in Scala, the classes cannot have static members. Instead, Scala enable creation of objects that are not associated to any class. These are called singleton objects. A singleton is like a class that can have only one instance.

/* singleton object demo */
object Main {
  //singleton object Id
  object Id {
    var i: Int = 0;
    def next(): Int = { i += 1; i }
  }
  //test singleton object: Id
  def main(args: Array[String]): Unit = {
    val id1 = Id.next()
    val id2 = Id.next()
    println(s"Id1=$id1")
    println(s"Id2=$id2")
  }
}

Companion Object

An singleton object with the same name as a class is called a companion object. A companion object can access the private members of its companion class. Also, a companion class can access its companion object. We use a companion object for methods and values which are not specific to instances of the companion class.

/* companion class */
class Demo {
    private val hidden = 10
}
/* companion object */
object Demo {
    def getHidden(self: Demo) = self.hidden
}
/* driver sngleton: object Main */
object Main {
  def main(args: Array[String]): Unit = {
    val obj = new Demo
    println(Demo.getHidden(obj)) // 10
  }
}

Usability: Companion objects are useful when you want to have a regular class that also have some static members. Then you create in addition to the class a singleton object that will contain all static members you need.

Case Classes

Case classes are designed to offer better support for functional programming. This is a special class that have some advantages over the regular class. Scala compiler is doing more work to generate better code behind the scene for these kind of classes.

Features:

Example:

/* case class */
case class Person(name: String, relation: String, age: Integer)

val p1 = Person("Christa", "niece",10)
val p2 = Person("Hanka", "niece",12)

//case classes can be cloned
val p3 = p1.copy(age = 21)

//case classes can be compared
p1 == p2 // false
p1 == p3 // false

Behaviour:

Due to features implemented, the case class is behaving different than a normal class.

Case Objects

A case object is like an enhanced object. It has more features than a regular object:

Features:

Note: We will create examples for case classes and case objects at the end of this tutorial when we know more about Traits, Enumerations and Flow Control. Let's continue with Traits.


Read next: Traits