21

I am trying to understand the Mixins in the context of scala. In particular I wanted to know difference between concepts of inheritance and Mixins.

The definition of Mixin in wiki says :

A mixin class acts as the parent class, containing the desired functionality. A subclass can then inherit or simply reuse this functionality, but not as a means of specialization. Typically, the mixin will export the desired functionality to a child class, without creating a rigid, single "is a" relationship. Here lies the important difference between the concepts of mixins and inheritance, in that the child class can still inherit all the features of the parent class, but, the semantics about the child "being a kind of" the parent need not be necessarily applied.

In the above definition, I am not able to understand the statements marked in bold. what does it mean that

  1. A subclass can inherit functionality in mixin but not as a means of specialization
  2. In mixins, the child inherits all features of parent class but semantics about the child "being a kind" the parent need not be necessarily applied. - How can a child extend a parent and not necessarily a kind of Parent ? Is there an example like that.
codeforester
  • 39,467
  • 16
  • 112
  • 140
Anveshan
  • 614
  • 1
  • 9
  • 21
  • In Scala, think of Mixins as a neat compile-time transformation that will decorate certain types with extra methods. In this case, while Scala keeps track of "mixed in types" for the type checker, method definitions themselves are *flattened* into the actual types so there is no parent-child established within the JVM classes. Inheritance is generally associated with a runtime polymorphic method resolution - but mixins are (largely) orthogonal concepts. Java 8 interface Default Methods are mixins as well. – user2864740 Apr 20 '16 at 03:43
  • This question does seem to have been [asked before in a broader context](http://stackoverflow.com/questions/860245/mixin-vs-inheritance) (although I don't feel completely satisfied by the answers there). – badcook Apr 20 '16 at 05:47
  • 1
    There is a very long answer describer in the book [Programming in Scala, 3rd edition][1], Chapter 12 Traits – Adelin Nov 08 '19 at 16:24

5 Answers5

20

I'm not sure I understood your question properly, but if I did, you're asking how something can inherit without really meaning the same thing as inheriting.

Mixins, however, aren't inheritance – it's actually more similar to dynamically adding a set of methods into an object. Whereas inheritance says "This thing is a kind of another thing", mixins say, "This object has some traits of this other thing." You can see this in the keyword used to declare mixins: trait.

To blatantly steal an example from the Scala homepage:

abstract class Spacecraft {
  def engage(): Unit
}
trait CommandoBridge extends Spacecraft {
  def engage(): Unit = {
    for (_ <- 1 to 3)
      speedUp()
  }
  def speedUp(): Unit
}
trait PulseEngine extends Spacecraft {
  val maxPulse: Int
  var currentPulse: Int = 0
  def speedUp(): Unit = {
    if (currentPulse < maxPulse)
      currentPulse += 1
  }
}
class StarCruiser extends Spacecraft
                     with CommandoBridge
                     with PulseEngine {
  val maxPulse = 200
}

In this case, the StarCruiser isn't a CommandoBridge or PulseEngine; it has them, though, and gains the methods defined in those traits. It is a Spacecraft, as you can see because it inherits from that class.

It's worth mentioning that when a trait extends a class, if you want to make something with that trait, it has to extend that class. For example, if I had a class Dog, I couldn't have a Dog with PulseEngine unless Dog extended Spacecraft. In that way, it's not quite like adding methods; however, it's still similar.

Nic
  • 6,211
  • 10
  • 46
  • 69
  • 2
    > `In this case, the StarCruiser isn't a CommandoBridge or PulseEngine` I really do not get how this is so, when I can define a method, say `launch(foo: CommandoBridge)` and call it so `launch(new StarCruiser())`...isn't the ability to pass an instance of `StarCruiser` to a method expecting `CommandoBridge` the canonical example of showing that `StartCruiser` is indeed *a* `CommandoBridge`? – dade Sep 09 '18 at 19:28
  • @dade It's more a case of awkward syntax than anything (how else would you get the `CommandoBridge` "out of" the `StarCruiser`?) There are certainly other ways, but none of them are particularly pretty, so the Scala designers went with what they thought best. If I had to guess their reasoning, I'd say it's because they didn't want to add additional syntax when they could overload an existing thing. – Nic Dec 21 '18 at 09:08
  • 1
    @dade I really don't like to sound like I am hating on Scala, but seems that Scala designers tried to correct some "problematic" concepts from other languages but ended up introducing even more complex and ambiguous ones. Letting developers to no to agree on one particular to create even more confusion! – Adelin Nov 08 '19 at 15:00
5

A trait (which is called mixin when mixed with a class) is like an interface in Java (though there are many differences) where you can add additional features to a class without necessarily having "is a" relationship. Or you can say that generally traits bundle up features which can be used by multiple independent classes.

To give you an example from Scala library, Ordered[A] is a trait which provides implementation for some basic comparison operations (like <, <=, >, >=) to classes that can have data with natural ordering.

For example, let's say you have your own class Number and subclasses EvenNumber and OddNumber as shown below.

class Number(val num : Int) extends Ordered[Number] {
  override def compare(that : Number) = this.num - that.num
}

trait Half extends Number {
  def half() = num / 2
}

trait Increment extends Number {
  def increment() = num + 1
}

class EvenNumber(val evenNum : Int) extends Number(evenNum) with Half

class OddNumber(val oddNum : Int) extends Number(oddNum) with Increment

In the example above, classes EvenNumber and OddNumber share is a relationship with Number but EvenNumber does not have "is a" relation with Half neither OddNumber share "is a" relation with Increment.

Another important point is even though class Number uses extends Ordered syntax, it means that Number has an implicit is a relationship with superclass of Ordered ie Any.

justAbit
  • 4,226
  • 2
  • 19
  • 34
  • "but EvenNumber does not have "is a" relation with Half neither OddNumber share "is a" relation with Increment." val h: Half = new EvenNumber(10) val i: Increment = new OddNumber(1) This compiles and executes perfectly, which makes the previous statement incorrect – Adelin Nov 08 '19 at 15:08
4

I think its very usage dependent. Scala being a multi-paradigm language makes it powerful as well as a bit confusing at times. I think Mixins are very powerful when used the right way. Mixins should be used to introduce behavior and reduce bolierplate.

A trait in Scala can have implementations and it is tempting to extend them and use them.

Traits could be used for inheritance. It can also be called mixins however that in my opinion is not the best way to use mixin behavior. In this case you could think of traits as Java Abstract Classes. Wherein you get subclasses that are "type of" the super class (the trait).

However Traits could be used as proper mixins as well. Now using a trait as a mixin depends on the implementation that is "how you mix it in". Mostly its a simple question to ask yourself . It is "Is the subclass of the trait truly a kind of the trait or are the behaviors in the trait behaviors that reduce boilerplate". Typically it is best implemented by mixing in traits to objects rather than extending the trait to create new classes.

For example consider the following example:

    //All future versions of DAO will extend this
trait AbstractDAO{
  def getRecords:String
  def updateRecords(records:String):Unit
}
//One concrete version
trait concreteDAO extends AbstractDAO{
  override def getRecords={"Here are records"}
  override def updateRecords(records:String){
    println("Updated "+records)
  }
}
//One concrete version
trait concreteDAO1 extends AbstractDAO{
  override def getRecords={"Records returned from DAO2"}
  override def updateRecords(records:String){
    println("Updated via DAO2"+records)
  }
}
//This trait just defines dependencies (in this case an instance of AbstractDAO) and defines operations based over that
trait service{
  this:AbstractDAO =>

  def updateRecordsViaDAO(record:String)={  
  updateRecords(record) 
  }
  def getRecordsViaDAO={
  getRecords
  }
}


object DI extends App{
  val wiredObject = new service with concreteDAO //injecting concrete DAO to the service and calling methods
  wiredObject.updateRecords("RECORD1")
  println(wiredObject.getRecords)

  val wiredObject1 = new service with concreteDAO1
  wiredObject1.updateRecords("RECORD2")
  println(wiredObject1.getRecords)

}

concreteDAO is a trait which extends AbstractDAO - This is inheritance

val wiredObject = new service with concreteDAO - This is proper mixin behavior Since the service trait mandates the mixin of a AbstractDAO. It would be just wrong for Service to extend ConcreteDAO anyways because the service required AbstractDAO it is not a type of AbstractDAO. Instead you create instances of service with different mixins.

Som Bhattacharyya
  • 3,972
  • 35
  • 54
2

The difference between mixin and inheritance is at semantic level. At syntax level they all are the same.

To mix in a trait, or to inherit from a trait, they all use extends or with which is the same syntax.

At semantic level, a trait that is intended to be mixed in usually doesn't have a is a relationship with the class mixining it which differs to a trait that is intended to be inherited.

To me, whether a trait is a mixin or parent is very subjective, which often time is a source of confusion.

1

I think it is talking about the actual class hierarchy. For example, a Dog is a type of Animal if it extends from the class (inheritance). It can be used wherever an Animal parameter is applicable.

mvd
  • 2,596
  • 2
  • 33
  • 47