Thursday, August 13, 2009

Traits and inheritance

Scala provides two structures for inheritance. Classes (abstract or not) and traits. Traits are very similar to Ruby Mixins meaning that they can contain code like abstract classes but like interfaces multiple traits can be inherited from.
Like interfaces traits cannot have constructors but in Scala variables can be abstract and therefore provide an easy way to simulate a constructor.
There are no method resolution conflicts because method definitions are always resolved right to left:
  1. class X extends Y with A with B with C

If ABC and Y all have the method (doit) the method in C will be used. If C calls super.doit that will call B.doit and so on.
Note: If Y defines doit the A, B, and C must define doit with the override keyword:
  1. override def doit() = {...}

In the above example ABC must be traits but Y can be a class or a trait. When inheriting you must always have one extends keyword which can optionally followed by one or more with clauses.

  1. scala> abstract class Animal {
  2.      |  val legs:Int
  3.      | val noise:String
  4.      | def makeNoise() = println(noise)
  5.      | }
  6. defined class Animal
  7. scala>  trait Quadriped {
  8.      | self:Animal =>
  9.      | val legs = 4
  10.      | }
  11. defined trait Quadriped
  12. scala> trait Biped {
  13.      | self:Animal =>
  14.      | val legs = 2
  15.      | }
  16. defined trait Biped
  17. scala> class Dog extends Animal with Quadriped {
  18.      | val noise = "Woof"
  19.      | override def makeNoise() = println( noise+" "+noise)
  20.      | }
  21. defined class Dog
  22. scala> new Dog().makeNoise()
  23. Woof Woof
  24. scala> abstract class GenericAnimal extends Animal{ 
  25.      | val noise = "glup"                          
  26.      | }
  27. defined class GenericAnimal
  28. scala> val quad = new GenericAnimal() with Quadriped
  29. quad: GenericAnimal with Quadriped = $anon$1@10bfb545
  30. scala> quad.makeNoise()
  31. glup
  32. scala> val biped = new GenericAnimal() with Biped
  33. biped: GenericAnimal with Biped = $anon$1@7669521
  34. scala> val biped = new GenericAnimal() with Biped{
  35.      | override val noise = "Hello"
  36.      | }
  37. biped: GenericAnimal with Biped = $anon$1@6366ce5f
  38. scala> biped.makeNoise()
  39. Hello

2 comments:

  1. You seem to have omitted the definition of GenericAnimal:

    abstract class GenericAnimal extends Animal {
    val noise = "glup"
    }

    Interesting series btw. I found out about it today from Planet Scala.

    ReplyDelete
  2. Thanks fixed. Also fixed the problem with copy and pasting the sample code into a terminal. (for this post). I will fix others over time.

    ReplyDelete