tags:

views:

144

answers:

2

What is the difference between following two?

1#

trait B extends A {

}

2#

trait B { self: A =>

}

where A is an abstract class.

>> EDIT:

Please explain with respect to the following example of Ducks with pluggable flying and quacking behaviors:

abstract class Duck {
  def fly(): Unit
  def quack(): Unit
  def swim() {
    println("Woodoowoodoowoodoo...")
  }
}

trait FlyingWithWings extends Duck {
  override def fly() {
    println("Me can fliez! :D")
  }
}

trait FlyingNoWay { self: Duck =>
  def fly() {
    println("Me cannot fliez! :(")
  }
}

trait Quack extends Duck {
  override def quack() {
    println("Quack! Quack!")
  }
}

trait MuteQuack { self: Duck =>
  def quack() {
    println("<< Silence >>")
  }
}

class MallardDuck extends Duck with FlyingWithWings with MuteQuack

object Main {
  def main(args: Array[String]) {
    val duck = new MallardDuck
    duck.fly()
    duck.quack()
  }
}

Output:

Me can fliez! :D
<< Silence >>

+1  A: 

In the first example B is a specialization of A. The second means that the trait B must always be mixed into something that is, or is a subtype of, A (which can be a class, trait or any other type).

Theo
No a trait can extend a class too
Aymen
I didn't know that, but I tried it out in the REPL and it works. You still can't have more than one class in the direct ancestry, though, so you can't get multiple inheritance (which was why I though you couldn't have traits extending classes).
Theo
+4  A: 

In the second case B can't be used in places where an A is expected, it's just designed to be "attached" to a certain A. So for instance in the first case A could be abstract and B could implement the missing methods, making it an instantiable type. This isn't possible in the second case, you need a "complete A", and only then you add some functionality.

So you could think of a "fits in a ..." relation instead of a "is a ..." relation.

Landei
Which one should be preferred? And why?
Jay Sinha
It depends if you really extend the base trait or not. E.g. if you have a trait Graph, a new trait ColoredGraph clearly "is a" (new kind of) graph and should extend the base trait. On the other hand if you add a trait with a method findCycles, this trait makes only sense when used together with Graphs, but it doesn't create a new kind of Graph, it just adds some functionality, so you would choose the second version with the self type in this case. For some cases the differences are not so clear, but with some experience you'll see which version fits better in your design.
Landei
@Landei: I don't think you got me. Let me try to rephrase. In my question, `A` is an `abstract class`, not a `trait`. In the example I have included, it's possible to plug in (or mix in) the behaviors in both ways. (`FlyingWithWings` uses extension whereas `MuteQuack` uses self type annotation.) So when should I prefer one way over another and why?
Jay Sinha
This is no real world example, but I would say it looks more naturally to extend here: FlyingWithWings and Quack are specifying more detailed what a Duck is.There is another explanation involving dependecy injection (but IMHO this is only one of their use cases): http://stackoverflow.com/questions/1990948/what-is-the-difference-between-scala-self-types-and-trait-subclassesAnd I found: "Sometimes it’s useful for a trait to be able to use the fields or methods of a class it is mixed in to, this can be done by specifying a self type for the trait." ( http://markthomas.info/blog/?p=92 )
Landei