Click here to Skip to main content
15,890,579 members
Articles / Programming Languages / Scala

Inheritance / Overriding / Traits

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
20 Oct 2015CPOL3 min read 11K   3   3
In this post, we will talk about how to create abstract classes, inheritance and also 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 keyword.

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:

C#
//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. Let's 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.

C#
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.

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

In this simple example, we have an 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.

C#
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:

C#
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:

C#
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:

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
QuestionA small mistake on the beginning... FIXED Pin
Paulo Zemek20-Oct-15 9:11
mvaPaulo Zemek20-Oct-15 9:11 
AnswerRe: A small mistake on the beginning... Pin
Sacha Barber20-Oct-15 9:51
Sacha Barber20-Oct-15 9:51 
AnswerRe: A small mistake on the beginning... Pin
Sacha Barber20-Oct-15 21:40
Sacha Barber20-Oct-15 21:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.