Inheritance / overriding / traits

 

In this post we will talk about how to create abstract classes, inheritance and also traits.

<Rant>

One thing I wanted to mention is that in Scala the focus is clearly on creating immutable data structures. Which is what YOU should be trying to achieve WHEREVER possible.

This means that you should be using var sparingly, really think about whether you DO need that field to be mutable, I would say ALWAYS favor val if you can, and only use var as a last resort.

In my last post I did actually show some code that true Scala devs would probably not do which is to accept var as constructor parameters. This was to illustrate a point about properties, but in reality this should have been using val instead.

</Rant>

Anyway rant over. Let’s carry on with the guts of this post, which to start of will be abstract classes.

 

Abstract Classes

In Scala much the same as other OO languages (looking at you here .NET), you can declare a class as abstract using the abstract key word.

Unlike .NET you do NOT mark the individual methods as “abstract”, you only make the class abstract. A method is abstract if the class is abstract and there is no implementation.

Here is an example of an abstract class, with a simple abstract method

//Primary constructor
abstract class PersonBase(val firstName: String, val lastName: String) {

  def ReportsTo() : String

  override def toString: String = {
    s"firstname: $firstName, lastname: $lastName, reportsTo : $ReportsTo"
  }
}

Inheritance

So now that we have an abstract class, how do we extend this abstract class. Lets see a couple of examples that extend the abstract class we specified above.

Here we have a Supervisor and CEO class, both of which want to use the PersonBase class as a super type.

So how do we do that in Scala?

Well it is actually quite simple, let’s see an example of the Supervisor and CEO classes.

class Supervisor(override val firstName: String, override val lastName: String, val budget: BigDecimal)
  extends PersonBase(firstName, lastName)
{
  override def ReportsTo(): String = "MD"
}



class CEO(override val firstName: String, override val lastName: String, val budget: BigDecimal)
  extends PersonBase(firstName, lastName)
{
  override def ReportsTo(): String = "None"
}

There are a couple of things to note above:

  • We use the extends keyword to extend the PersonBase class (which makes PersonBase the super type of the current type (i.e. Supervisor / CEO)
  • We use the override keyword a couple of times in the primary constructor for these new Supervisor / CEO classes
  • We use the override keyword on the method def to override the super types ReportsTo() method

 

In a nut shell that is the basics of how to inherit from a class and override methods / primary constructor parameters

 

Interfaces

In Scala there are no interfaces, instead there are traits. We will look at those next

 

Traits

Traits are like abstract classes, and are used to define object types by specifying the signature of the supported methods. Traits may be partially implemented, and a type may also inherit from MULTIPLE traits. What multiple inheritance, yep you can do that.

Yikes

In contrast to classes, traits may not have constructor parameters.

Lets see an example of a simple trait that mimics a 2 input AND logic gate, which also has a NAND method too.

In this simple example, we have a abstract method “and” which needs to implemented, but we also have a nand method which is already implemented. So the inheritor of this trait ONLY needs to supply an implementation for the “and” method.

trait AndGate {
  def and(x1: Boolean, x2: Boolean): Boolean
  def nand(x1: Boolean, x2: Boolean): Boolean = !and(x1, x2)
}


class LogicGate() extends AndGate {

  def and(x1: Boolean, x2: Boolean): Boolean =
    x1 && x2

}

Which we are able to use like this:

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

    val lg = new LogicGate()
    val and1Result = lg.and(true,false)
    val nand1Result = lg.nand(true,false)
    System.out.print(s"lg.and : $and1Result,lg.nand : $nand1Result \r\n")

    val and2Result = lg.and(true,true)
    val nand2Result = lg.nand(true,true)
    System.out.print(s"lg.and : $and2Result,lg.nand : $nand2Result \r\n")


    System.in.read()

    ()
  }

}

Which when run looks like this:

image

 

The other interesting thing about traits, is that you may have multiple traits, and they may even have the same method. For example what about this, what do you think happens here:

trait LoggerBase
{
  def log(input : String): Unit
}


trait Logger extends LoggerBase {
  override def log(input : String): Unit = {
    System.out.print(s"Logger :input = '$input'\r\n")
  }
}

trait AnotherLogger extends LoggerBase {
  override def log(input : String): Unit = {
    System.out.print(s"AnotherLogger input = '$input'\r\n")
  }
}


//This class inherits from 2 Traits, both with same
//method implemented
class SomeWeirdLogger() extends Logger with AnotherLogger {

}

Do you think we will see this output

AnotherLogger input = ‘What gives’

or this output

Logger input = ‘What gives’

 

Well we actually get this output

image

But why is this?

What would happen if we reversed the order to this

trait LoggerBase
{
  def log(input : String): Unit
}


trait Logger extends LoggerBase {
  override def log(input : String): Unit = {
    System.out.print(s"Logger :input = '$input'\r\n")
  }
}

trait AnotherLogger extends LoggerBase {
  override def log(input : String): Unit = {
    System.out.print(s"AnotherLogger input = '$input'\r\n")
  }
}


//This class inherits from 2 Traits, both with same
//method implemented
class SomeWeirdLogger() extends AnotherLogger with Logger  {

}



 

Where we have swapped the order of the inherited traits.

Now we get this output. Mmm Strange.

image

Basically traits DO HAVE an order, and the outer most one wins

 

 

 

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: