Scala Polymorphic Methods and Explicitly Typed References

Filed Under: Scala

The methods in scala can be parametrized with both value and types. Value parameters are enclosed within a pair of parenthesis whereas type parameters within a pair of brackets. For example;

polymorphic.scala


object polymorphic {
  def main(args: Array[String]) {
    def add(a: Int, b: Int) {
      val c = a + b;
      println(c)
    }

    def addStrings(a: String, b: String) {
      val s = a + b
      println(s)
    }

    add(72, 67);
    addStrings("Hello", "World");
  }
}

In this example the + plus operator is used for adding numbers as well as concatenating the strings. The add method performs the addition of two numbers and returns the result. The addString method use the same + operator and concatenates the two strings specified by the user. This is default operator polymorphism provided by Scala. Below image shows the output produced by the above program.

Scala-Operator-Polymorphism

Scala Method Polymorphism

Now let’s see an example of polymorphism in method. We will write a generic method to get the list where we will pass the type, default values and number of items in the list.

PolymorphicMethod.scala


object PolymorphicMethod {
  def getList[T](x:T, y:Int): List[T] = {
    if (y == 0)
      Nil
    else
      x :: getList(x, y - 1)
  }
      
    def main(args: Array[String]) {
      println(getList[Int](3,2))
      println(getList[String]("Hi", 3))
    }
}

Below image shows the output produced when above program is executed in the Scala IDE.

Scala-Polymorphic-Methods

Scala Explicitly typed References

Sometimes we need to explicitly specify the type of value “this” in a program. Let’s see an example for this scenario.

We have a Train abstract class as below.

Train.scala


abstract class Train {
  type Link;
  type Compartment <: CompartmentIntf
  abstract class CompartmentIntf {
    def join(compartment: Compartment): Link
  }
  def compartments: List[Compartment]
  def links: List[Link]
  def addCompartment: Compartment
}

The abstract class Train consists of List of links and compartments. The abstract class CompartmentIntf is defined and contains join method which takes Compartment as parameter. The methods compartments, links and addCompartment are declared but the implementation will be defined in concrete classes.

Now we will define the abstract class MetroTrain that extends train class as;

MetroTrain.scala


abstract class MetroTrain extends Train {

  type Link <: LinkImpl
  class LinkImpl(comptA: Compartment, comptB: Compartment) {
    def c1 = comptA
    def c2 = comptB
  }

  class CompartmentImpl extends CompartmentIntf {
    def join(compartment: Compartment): Link = {
      val link = newLink(this, compartment)
      links = link :: links
      link
    }
  }

  protected def newCompartment: Compartment
  protected def newLink(c1: Compartment, c2: Compartment): Link
  var compartments: List[Compartment] = Nil
  var links: List[Link] = Nil
  def addCompartment: Compartment = {
    val compartment = newCompartment
    compartments = compartment :: compartments
    compartment
  }
}

This class provides a partial implementation extending Train class. The implementation details are open and thus link and compartment are left abstract. We add factory methods newLink and newCompartment since it is required to create new compartment and link objects. The methods addCompartment and join are defined using factory methods.

However above class will throw compilation error in line no 11 as “type mismatch; found : CompartmentImpl.this.type (with underlying type MetroTrain1.this.CompartmentImpl) required: MetroTrain1.this.Compartment” because “this” is assigned the type CompartmentImpl, so it’s not compatible with type Compartment required by the corresponding factory method.

Let us solve this type mismatch by using explicitly typed self reference for CompartmentImpl as below.


class CompartmentImpl extends CompartmentIntf {
  self: Compartment =>
  def join(compartment: Compartment): Link = {
    val link = newLink(this, compartment)
    links = link :: links
    link
  }
}

According to the new definition of CompartmentImpl, this has type Compartment. We specify the explicit typed reference so that CompartmentImpl denotes sub type of Compartment to be instantiate.

We will now define a concrete class ConcreteMetroTrain as;

ConcreteMetroTrain.scala


class ConcreteMetroTrain extends MetroTrain {
  type Link = LinkImpl
  type Compartment = CompartmentImpl
  protected def newCompartment: Compartment = new CompartmentImpl
  protected def newLink(c1: Compartment, c2: Compartment): Link =
    new LinkImpl(c1, c2)
}

We can now instantiate CompartmentImpl because now we know that CompartmentImpl denotes a subtype of type Compartment. Now create a Scala object TestTrain as;

TestTrain.scala


object TestTrain {
  def main(args: Array[String]) {

    println("Linking Compartments.....")
    val t: Train = new ConcreteMetroTrain
    val c1 = t.addCompartment
    val c2 = t.addCompartment
    val c3 = t.addCompartment
    c1.join(c2)
    c2.join(c3)
  }
}

That’s all for polymorphic methods and explicitly typed references in scala programming, we will look into more scala features in coming posts.

Leave a Reply

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

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages