en

Inheritance - Scala for the impatient

10 Apr 2019 | 3mins

This is the second part of my contribution to Gympass’ Scala study group. Scala for the Impatient, chapter 8: Inheritance.

Inheritance

Inheritance is the mechanism that allows a child class to access properties( defs/ vals/ vars) of its parent classes*.( or traits/ case classes/ abstract classes etc.).

We will learn how inheritance works in Scala. Highlights:

Extending a Class

  
    class Employee extends Person {
      var salary: 0.0
      ...
    }
  

We can specify fields and methods that are new to the subclass or that overrides properties of the superclass.

It is possible to declare class final so that cannot be extended. It is also possible to do this to individual methods or fields so it can’t be overridden.

Overriding Methods

We must use override when you override a method that isn’t abstract

  
    public class Person {
    ...
      override def toString = getClass.getName + "[name=" + name + "]"
    }
  

Invoking a superclass method using super:

  
    public class Employee extends Person {
      ...
      override def toString = super.toString + "[salary=" + salary + "]"
    }
  

Type Check and Casts

Use isInstanceOf to test if an object belongs to a class or a subclass of it. The method asInstanceOf is used to convert an object to a specific subclass.

    
      if (p.isInstanceOf[Employee]) {
      val s = p.asInstanceOf[Employee] // s has type Employee
      ...
      }
    

if you want to test an object to a specific class (without subclasses) use:

    
      if (p.getClass == classOf[Employee])
    

However, pattern matching is usually better than using type check and casts.

Protected Fields and Methods

A method or field can be declared as protected and it can be visible only for subclasses, and not throughout the package.

Superclass Construction

The primary constructor is intertwined with the class definition. The call to the superclass too.

    
      class Employee(name: String, age: Int, val salary : Double) extends Person(name, age)
    

Overriding Fields

You can override fields with another field with the same name.

These are the restrictions:

OBS: A var cannot be overridden. If you provide a var, all subclasses will be stuck with it

Anonymous Subclasses

An anonymous subclass is created when you include a block with definitions or overrides. (Object with structural type) Ex:

    
      val alien = new Person("Fred") {
        def greeting = "Greetings, Earthling! My name is Fred."
      }
    

Abstract Classes

Use abstract to create classes that cannot be instantiated. Used when one or more methods are not defined.

No override needed on subclasses.

Abstract Fields

An abstract field is a field without an initial value.

No override needed on subclasses.

Construction Order and Early Definitions

Construction order problem. Not sure when it occurs…

early definition syntax is used instead of final or lazy

You place the val fields in a block after the extends keyword:

    
      class Bug extends {
        override val range = 3
      } with Creature
    

The Scala Inheritance Hierarchy

Scala Classes Hierarchy Diagram

Object Equality

When we write a class we should consider overriding the equals method to provide an accurate representation for our class.

Ex:

    
      Class Item(val description: String, val price: Double)
      ...

      final override def equals(other: Any) = {
        val that = other.asInstanceOf[Item]
        if (that == null) false
          else description == that.description && price == that.price
        }
    

OBS: The equals override only works for parameters with type Any.

OBS2: Do not forget to override the HashCode too. Use only fields you use on equality check.

    
      final override def hashCode = 13 * description.hashCode + 17 * price.hashCode
    

In a normal application simply use == operator.

Hey, thanks for reading :D ! Any thoughts on this topic? Comment below! ;)