I have a FAMILY of types that I want to modularly "enrich" using mixins. For example:
trait Family {
self =>
trait Dog {
def dogname:String
def owner:self.Person
}
trait Person {
def name:String
def pet:self.Dog
}
}
trait SerializableFamily extends Family {
trait Dog extends super.Dog {
def toSimpleString:String = "Dog(" + dogname + ")"
}
trait Person extends super.Person {
def toSimpleString:String = "Person(" + name + ") and his pet " + pet.toSimpleString
}
}
trait SerializableFamily2 extends Family {
trait Dog extends super.Dog {
def toLoudString:String = "Dog(" + dogname.toUpperCase + ")"
}
trait Person extends super.Person {
def toLoudString:String = "Person(" + name.toUpperCase + ") and his pet " + pet.toLoudString
}
}
However, the above does not work ( Scala 2.9.1 ). The last expression fails to compile ( pet.toSimpleString
).
This is just a random strategy I picked out of several I tried: self typing, abstract types, super[...], etc.
I want to be able to do something like this, eventually:
val family = new Family with SerializableFamily with TraversableFamily with FooFamily {}
Where each mixin adds a set of cooperating methods to one or more types within the family.
This is a common pattern that I have seen solved by using implicit wrappers, pattern-matching based visitors, etc. But since it is just a recursive application of the regular mixin pattern I wonder if there might be a simpler way to achieve it.
The error in your case is expected, since Dog
and Person
in mixins don't override Dog
and Person
in Family
, so that self.Person
still refers to Family.Person
.
This may be closer to what you want
trait Family {
// type DogType = Dog won't work because then two different mixins
// have incompatible DogType implementations
type DogType <: Dog
type PersonType <: Person
trait Dog {
def dogname:String
def owner:PersonType
}
trait Person {
def name:String
def pet:DogType
}
}
trait SerializableFamily extends Family {
type DogType <: Dog
type PersonType <: Person
trait Dog extends super.Dog {
def toSimpleString:String = "Dog(" + dogname + ")"
}
trait Person extends super.Person {
def toSimpleString:String = "Person(" + name + ") and his pet " + pet.toSimpleString
}
}
But then you have something yucky like
new Family with SerializableFamily with TraversableFamily with FooFamily {
type DogType = super[SerializableFamily].Dog with super[TraversableFamily].Dog with super[FooFamily].Dog
}