Inheritance

As in Java, classes can extend other classes. If class B extends class A, then B inherits the fields and methods of A. (Of course these fields and methods must be public or protected in order for B to access them.)

For example, assume a calculator class is declared in Scala:

class Calculator {
  protected var result = 0.0
  def add(x: Double) { result += x }
  def mul(x: Double) { result *= x }
  def div(x: Double) { result /= x }
  def sub(x: Double) { result -= x }
  def clear { result = 0.0 }
  def getResult = result
  def help {
    println("Commands: add, mul, div, sub, clear, getResult, help")
  }
}

We can create a math calculator by extending the Calculator class:

class MathCalculator extends Calculator {
  def sin { result = math.sin(result) }
  def cos { result = math.cos(result) }
  def tan { result = math.tan(result) }
  override def help {
    super.help
    println("Also: sin, cos, tan")
}

The Calculator field and methods are inherited:

object TestCalculator extends App {
     val calc = new MathCalculator
     calc.add(12)
     calc.mul(3)
     calc.div(2)
     calc.sin
     println(calc.getResult) // prints -0.7509872467716762
     calc.help // calls MathCalculator.help which calls Calculator.help
}

Notes:

·       Class members can have public, private, and protected scope. Public members (the default) can be accessed by any client of the class. Private members can only be accessed by other members of the class. Protected members can be accessed by class members and members of subclasses. (How is this different from Java's definition of protected scope?)

·       A class can override (i.e., redefine) inherited fields and methods, but must declare the override.

·       An override may call the method over ridden.

Here's how subclasses are represented in UML

image006

The Scala class hierarchy

Scala data can be divided into values and references. Values are objects that wrap primitive values such as Int, Boolean, and Double. All other objects are references. Here's the Scala inheritance hierarcy:

 

 

Notes:

·       Any is the root of the Scala class hierarchy. Its methods include:

==, !=, equals
hashCode, ##
isInstanceOf, asInstanceOf
toString

·       AnyVal is the root of all value types (i.e., wrappers for primitive values). Implicit subtype conversions are defined between these classes.

·       AnyRef is the root class for all reference types (pointers to objects in the heap). In addition to the inherited methods, it adds:

getClass // returns an instance of java.lang.Class

·       Unit is analogous to Java's void type. Its only instance is ().

·       The only instance of Null is null, the null reference pointer. It can masquerade as any reference.

·       Nothing is the empty class. It is the universal subtype.

Runtime Type Identification

MathCalculator extends Calculator, hence is a subtype of calculator. By the subsumption rule, this implies math calculators can masquerade as calculators:

var calc2: Calculator = null
calc2 = new MathCalculator

Why does the following command fail?

calc2.sin

To remedy the situation we can perform a safe cast:

if (calc2.isInstanceOf[MathCalculator]) {
    val calc3 = calc2.asInstanceOf[MathCalculator]
    calc3.sin
    println(calc3.getResult)
}

We can use reflection to do the same thing:

if (calc2.getClass == classOf[MathCalculator]) {
    // as above
}

Abstract Classes

An abstract class contains one or more abstract methods. An abstract method is simply a method without an implementation:

abstract class Shape {
     def area: Double
}

Abstract classes can't be instantiated for obvious reasons.

A class that inherits an abstract method is also abstract unless it provides implementations for those methods:

class Rectangle(length: Double, width: Double) extends Shape {
     def area = length * width
}

Notes:

·       We don't need to declare that a method overrides an inherited abstract method.

·       We don't need to perform casts. Thanks to polymorphism, the right method always gets called:

var shape: Shape = new Rectangle(3, 4)