Is Traits in Scala an Interface or an Abstract Class?

Pardeep Sharma

I have read over the internet that Traits in Scala are

interfaces that can provide concrete members

this means, traits are interface and we may provide body to methods in interface. I have a simple query here, if that is possible than why my below code shows error:

Error:(6, 8) object Car inherits conflicting members: method startEngine in trait Vehical of type => Unit and method startEngine in trait Motor of type => Unit (Note: this can be resolved by declaring an override in object Car.) object Car extends Vehical with Motor {

trait Vehical {
  def startEngine : Unit = {
    println("Vehical Start")
  }
  def stopEngine
}

trait Motor {
  def startEngine : Unit = {
    println("Motor Start")
  }
  def stopEngine
}

object Car extends Vehical with Motor {

  override def stopEngine : Unit = {
    println("Stop Engine")
  }

  def main(args: Array[String]): Unit = {
    Car.startEngine
    Car.stopEngine
  }
}

Being a java developer I would have not provided body inside interface but scala traits allowed this. If traits are not interface then I'll consider them as an abstract class, that means no interface allowed in scala.

Also please let me know how to resolve this ambiguity problem. How can I use my startEngine method in child class if the same method is available in multiple traits.

Yuval Itzchakov

Being a java developer I would have not provided body inside interface but scala traits allowed this

A trait in Scala provides means of defining a default implementation, and so does Java starting version 8. In Scala, they are primarily used as mixins.

In regards to the compilation error, this arises from the fact that you have declared both Vehicle and Motor with a startEngine method, and that creates an ambiguity from the compilers point of view, since you're mixing in both implementations. To overcome this, you need to explicitly override the method in the implementing class/trait:

override def startEngine: Unit = super.startEngine

One important thing to note is that super here is referring to the last trait in the mixin chain which supplies a startEngine method, in this case Motor. This means that you'll see:

Motor Start
Stop Engine

Which I'd argue is not what you want.

What can be done is to require Vehicle to have a mixed in Motor implementation using self types:

trait Vehicle {
  self: Motor =>

  def startEngine: Unit = {
    println("Vehicle Start")
    startMotor
  }

  def stopEngine: Unit = {
    println("Stopping Engine")
    stopMotor
  }
}

And define your Motor methods in terms of motor only:

trait Motor {
  def startMotor: Unit = {
    println("Motor Start")
  }

  def stopMotor: Unit = {
    println("Stop Motor")
  }
}

And then you mixin everything:

object Car extends Vehicle with Motor

And call:

def main(args: Array[String]): Unit = {
  Car.startEngine
  Car.stopEngine
}

And you get:

Vehicle Start
Motor Start
Stopping Engine
Stop Motor

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related