( 9) Class Hierarchies

(9) Class Hierarchies

About

:octocat: GitHub: All of the example code: repo (link)

:page_facing_up: blog link: https://purrgramming.life/cs/programming/fp/ :star:


Terminology

  1. Abstract Classes: An abstract class may include abstract methods or abstract properties shared by its subclasses.

  2. Extend: the extends keyword indicates that the class being defined is derived from the base class using inheritance. i.e. extend the functionality of the parent class to the subclass.

image source: https://www.geeksforgeeks.org/difference-between-abstract-class-and-interface-in-java/

file

  1. Conformance: an object of subtypes can be used wherever an object of
    parent type is required

  2. Base Class: A class from which other classes are derived.

Abstract Classes

Definition

Scala has a concept of an abstract class similar to Java’s abstract class, constructed using the abstract keyword.

Need to use an abstract class when:

  • You want to create a base class that requires constructor arguments
  • Your Scala code will be called from Java code

Consider the task of writing a class for sets of integers with the following operations.

abstract class IntSet {  
  def incl(x: Int): IntSet  
  def contains(x: Int): Boolean  
}

IntSet is an abstract class.

Abstract classes can contain members who are missing an implementation (in our case, both incl and contains);

These are called abstract members.

Consequently, no direct instances of an abstract class can be created. For instance, an IntSet() call would be illegal.

Abstract Function

An abstract function) is a virtual function for which we can (and must) implement the derived class. Otherwise, the derived class will also become an abstract class

The definitions of contains and incl in the classes Empty and NonEmpty implement the abstract functions in the base class IntSet

abstract class IntSet {  
  def incl(x: Int): IntSet  // Abstract Function
  def contains(x: Int): Boolean  // Abstract Function
}

Abstract classes can contain both abstract and non-abstract methods.

class Empty() extends IntSet {  
  def contains(x: Int): Boolean = false  // Implementation 
 def incl(x: Int): IntSet = NonEmpty(x, Empty(), Empty())  // Implementation 
}

Class Extensions

IntSet is called the superclass of Empty and NonEmpty.
Empty and NonEmpty are subclasses of IntSet.

In Scala, any user-defined class extends another class.
If no superclass is given, the standard class Object in the Java package. So, the base classes of NonEmpty include IntSet and Object.

Let’s consider implementing sets as binary trees.

There are two types of possible trees:

  1. a tree for the empty set
  2. a tree consisting of an integer and two sub-trees.

Here are their implementations:


class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet {  
  def contains(x: Int): Boolean =  
    if x < elem then left.contains(x)  
  else if x > elem then right.contains(x)  
  else true  

 def incl(x: Int): IntSet =  
    if x < elem then NonEmpty(elem, left.incl(x), right)  
  else if x > elem then NonEmpty(elem, left, right.incl(x))  
  else this  
}  

class Empty() extends IntSet {  
  def contains(x: Int): Boolean = false  
 def incl(x: Int): IntSet = NonEmpty(x, Empty(), Empty())  
}
  1. Empty and NonEmpty both extend the class IntSet.
  2. This implies that the types Empty and NonEmpty conform to the type IntSet, i.e. an object of type Empty or NonEmpty can be used wherever an object of type IntSet is required.

file

Dynamic Binding

Object-oriented languages (including Scala) implement dynamic method dispatch.

This means that the code invoked by a method call depends on the object’s runtime type that contains the method.

i.e. Dynamic binding is determining the method to invoke at runtime
instead of at compile-time
.

Dynamic binding is also referred to as late binding.

// val res1: Boolean = false  
Empty.contains(1)  

//val res2: Boolean = true  
(NonEmpty(7, Empty, Empty)).contains(7)

Summary

Abstract classes

  • can have companion objects
  • can extend other classes (there are no restrictions on this, abstract classes can extend and be extended by abstract or non-abstract classes)
  • cannot be instantiated (abstract classes contain members without implementation. Therefore, they cannot be instantiated)
  • can be extended

Clean Code

In the IntSet example, there is really only a single empty IntSet.
So overkill to have the user create many instances of it.

We can express this case better with an object definition:

object Empty extends IntSet {  
  def contains(x: Int): Boolean = false  
 def incl(x: Int): IntSet = NonEmpty(x, Empty, Empty)  
}

This defines a singleton object named Empty.
No other Empty instance can be (or needs to be) created.

Singleton objects are values, so Empty evaluates itself.

i.e.

// val res0: Boolean = false  
Empty.contains(1)  
// Error: value contains is not a member of object NonEmpty  
NonEmpty.contains(1)

Also, we can create a companion object for IntSet.

object IntSet {  
  def singleton(x: Int) = NonEmpty(x, Empty, Empty)  
}

This defines a method to build sets with one element, called IntSet.singleton(elem).

Overriding

It is also possible to redefine an existing, non-abstract definition in a subclass by using override.

i.e., a feature that enables a child class to provide a different implementation for a method already defined and/or implemented in its parent class or one of its parent classes.

image source: https://codepumpkin.com/method-overriding-interview-questions/

file


// Creating a super class  
abstract class Shapes {  
  def draw() = println("Draw the shape")  

}  

// Creating a subclass  
class Rectangle extends Shapes  

// Creating a subclass  
class Circle extends Shapes {  
  // Overriding   
 override def draw() = println("Draw the Circle")  
  }  

val rectangle = new Rectangle  
rectangle.draw()  

val circle = new Circle  
circle.draw()

Results:

val rectangle: Rectangle = Rectangle@47a8e61f
Draw the shape

val circle: Circle = Circle@15c2d397
Draw the Circle

Leave a Reply

Your email address will not be published. Required fields are marked *