When to use self references or composition?

2020-03-26 07:50发布

问题:

Hve a look to the following code snippet:

trait T { def y = println("hello") }
class A {
   self: T =>
   def x = y
}
abstract class B {
   val self: T
   def x = self.y
}

val a = new A with T
val b = new B with T {
   val self = this
}
a.x
b.x

Class A and B have a reference to trait T, A has a self reference and B is using composition.

I see only two differences here: The first is in creating new objects and the second in accessing T.

In B there is more syntactic sugar, I don't need to explicitly access reference self and I don't need to bind the variable.

Are there another differences and are there some situations in which one should preferred instead of the other?

回答1:

Your question seems to excludes plain inheritance. For A, the self type has no advantage compared to class A extends T. For B, if you intend to create it only as written, that is with self = this, extends is just as good too (and so much simpler)

I don't think there are that many use case for self type (but this is not a discussion of composition vs inheritance)

One of them is to force a trait to be instanciated only as a subtype of another type not yet known, because it appears as a type parameter or an abstract type member. For instance, trait X[A] {self: A => ...} You can have a look at this realistic example on the scala site, with a type member.

Another is when you are composing modules, rather than instances, in particular when module have type members, making composition feasible only at compile time. This is more or less related to the CakePattern.

Composition (whether with abstract val or constructor parameter) has of course the strong advantage that you can pass an external instance of T, share it between different instances of B, choose it much more dynamically. instances may be passed to and returned from functions, mixins cannot



回答2:

In scala, I only use composition when I must "mix" a class in another one. In your example, if T was a class:

class T { def y = println("hello") }

then new X with T would not be possible.



标签: scala