Family Polymorphism + Mixins? - scala

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
}

Related

How can I reference a companion object's method in a generic class?

So I am a bit new to scala.
How does one write scala code to reference a method from case class's companion object in a generic fashion? I have tried a couple of different approaches and can't seem to find one that works.
Below is some sample code that works, but I have to manually build each subclass.
For example:
class One extends Act[LetterA] {
val intro = LetterA.sayhi
}
I would much rather do something like:
class AllOfThem[T <: LettersClass, S <: LettersSingleton] extends Act[T] {
val intro = S.sayhi
}
but I can't seem to find syntax that works or will compile. What is the proper way to do this, or am I looking for something that is not supported in the language? I recognise I am probably a little off on how I am structuring my classes and traits, but I am not sure how to best tackle this desired behaviour.
Additionally, is there a way to something similar to what I have commented out in the method 'actionTwo' in the Act class?
Sample Code listing:
trait LettersSingleton {
def sayhi() : String
}
trait LettersClass {
val id : Int
}
// trait Letters extends LettersClass with LettersSingleton { }
object LetterA extends LettersSingleton {
def sayhi = "Hi I am A"
}
object LetterB extends LettersSingleton {
def sayhi = "Hi I am B"
}
case class LetterA( val id : Int ) extends LettersClass { }
case class LetterB( val id : Int, val name:String ) extends LettersClass { }
abstract class Act[ T <: LettersClass ] {
val intro : String
def actionOne( a : T ) = {
println( a.id + " is my id" )
}
def actionTwo() = {
// println( T.sayhi )
}
}
class One extends Act[LetterA] {
val intro = LetterA.sayhi
}
class Two extends Act[LetterB] {
val intro = LetterB.sayhi
}
So you can't do exactly what you want, but you can get very close with the commonly used typeclass pattern:
//add a type parameter, now you have a typeclass
trait LettersSingleton[T] {
def sayhi() : String
}
//LettersClass stays the same
object Implicits {
//implicit classes/objects have to go inside an object
//create typeclass instances as implicit objects
implicit object LetterASingleton extends LettersSingleton[LetterA] {
def sayhi = "Hi I am A"
}
implicit object LetterBSingleton extends LettersSingleton[LetterB] {
def sayhi = "Hi I am B"
}
}
import Implicits._
//add an implicit parameter to the class
abstract class Act[ T <: LettersClass ](implicit singleton: LettersSingleton[T]) {
def actionTwo() = {
println( singleton.sayhi )
}
}
(new Act[LetterA]).actionTwo() //prints "Hi I am A"
(new Act[LetterB]).actionTwo() //prints "Hi I am B"
So basically what happens is any time you create a new Act[T], the compiler is going to try to fill in the implicit parameter for you by looking for any implicit objects or vals of the correct type in scope. So
val a = new Act[LetterA]
will actually become
val a = new Act[LetterA](LetterASingleton)
You'll notice that the singletons are no longer the companion objects of the case classes, which is fine. You have to define a trait regardless, so it doesn't make much different whether it's the companion object or some other object that implements it.

Advise on exercise with scala abstract types

I'm looking for an advise on this exercise I'm doing - specifically, what areas can be improved/shortened? I don't like that to feed the animals I have to use asInstanceOf but cannot find a better way. An idea is that I need to run this function for millions of objects so performance is important.
P.S. Would generics perform better in my case?
trait Animal {
type suitableFood
def eat(f: suitableFood)
}
trait Food
case class Grass (val color: String) extends Food
case class Fish (val size: String, val condition: String) extends Food
trait GrassT{
type suitableFood = Grass
}
trait FishT{
type suitableFood = Fish
}
class Cow extends Animal with GrassT{
def eat (f: suitableFood) = {
println("moo " + f.color)
}
}
class Sheep extends Animal with GrassT{
def eat (f: suitableFood) = {
println("baaa " + f.color)
}
}
class Cat extends Animal with FishT{
def eat (f: suitableFood) = {
println("mew " + f.size + " " + f.condition)
}
}
val cow = new Cow
val sheep = new Sheep
val whiteCat = new Cat
val blackCat = new Cat
val fish = new Fish("small", "fresh")
val grass = new Grass("green")
val cats = List(whiteCat, blackCat)
val farmAnimals = List(sheep, cow)
def feedAnimals[F <: Food](food: F, animals: List[Animal]) = {
animals.foreach(a => a.eat(food.asInstanceOf[a.suitableFood]))
}
feedAnimals(grass, farmAnimals)
feedAnimals(fish, cats)
You just need to put a stricter type restriction on feedAnimals:
def feedAnimals[F <: Food](food: F, animals: List[Animal { type suitableFood = F }]) =
animals.foreach(_.eat(food))
Or:
def feedAnimals[F <: Food, A <: Animal { type suitableFood = F }](food: F, animals: List[A]) =
animals.foreach(_.eat(food))
Unlike the solution using asInstanceOf, these solutions will fail at compile time (as opposed to runtime) for statements like feedAnimals(grass, cats), as desired.
Generics might be simpler in this case, if you prefer.

Generic traits with companion object

I am using scala 2.10. I am still (very) new to scala and I am not able to understand why I cant access name field of Person case class inside the print method of trait Printer[T].
This is the sample code:
it prints out
Person(Mark)
Person(Will)
// Model
abstract class BaseModel[T] {
def all: List[T]
}
case class Person(name: String)
object Person extends BaseModel[Person] {
val people = Set(Person("Mark"), Person("Will"))
def all = people.toList.sortBy(_.name)
}
// Controller
trait Printer[T] {
val model: BaseModel[T]
def print = model.all.foreach { p =>
// p.name gives error "value name is not a member of type parameter T"
println(p)
}
}
object PersonPrinter extends Printer[Person] {
val model = Person
}
// Call
object MyApp extends App {
PersonPrinter.print
}
If you put no constraints to T, that is, say some requirements about it, you cannot 'know' that you can call any specific method (except toString, hashCode, equals and some more methods that exists on all objects).
One way you could do that is by not using a generic like you do at all, but instead be specific:
trait Printable {
def text: String
}
trait Printer {
def model: BaseModel[Printable]
def print = model.all.foreach(p => println(p.text))
}
Or you could use a type bound for your T that expresses a requirement for what T is allowed to be:
trait Printer[T <: Printable] {
def model: BaseModel[T]
def print = model.all.foreach(p => println(p.text))
}
This way you can only create implementations of Printer where the concrete type you put in implements the Printable trait.
I guess this would compile:
trait Printer[T<:Person] {
val model: BaseModel[T]
def print = model.all.foreach { p =>
// p.name gives error "value name is not a member of type parameter T"
println(p.name)
}
}
or using structural typing:
trait Printer[T<: {val name:String}] {
val model: BaseModel[T]
def print = model.all.foreach { p =>
// p.name gives error "value name is not a member of type parameter T"
println(p.name)
}
}

Scala abstract inheritance

So, what I want to do is to create an abstract inheritance model using traits. I think example code works best so I created this small showcase to present my problem.
trait Animals{
val owned: Seq[Animal]
type Animal <: TAnimal
trait TAnimal {
def name : String
}
}
So far so good. Now I have another trait "Dogs". The dogs are chipped so they have and identification Number. Also I want to implement the sequence containing all the dogs I have (lets say I have 5 dogs with random names and random identNo, for simplicities sake).
trait Dogs extends Animals{
type Dog <: TDog
val owned = ???
trait TDog extends TAnimal {
def identNo : Int
}
}
The Problem is, since Animal or Dog are only types I cannot create concrete instances of them.
I think I can use something like Seq.fill but I'm not able to create a matching expression.
This is called a Cake Pattern. And you don't need to write all this stuff in Dog trait, you can define it like this:
trait Animals{
type Animal <: TAnimal
def owned: Seq[Animal]
trait TAnimal {
def name : String
}
}
trait Dogs extends Animals{
type Animal <: TDog
trait TDog extends TAnimal {
def identNo : Int
}
}
Then "at the end of the world" you assemble your cake with some concrete implementation:
trait ReservoirDogs extends Dogs {
case class Animal(name: String, identNo: Int) extends TDog
val owned = List(Animal("Pink", 1), Animal("Blue", 2))
}
Now you can mix it in:
scala> val dogs = new Dogs with ReservoirDogs {}
dogs: Dogs with ReservoirDogs = $anon$1#6f6f6727
scala> val dogs = new Animals with ReservoirDogs {}
dogs: Animals with ReservoirDogs = $anon$1#11c8ce34
This is what Cake Pattern is all about

Combinatorial Subtyping (in Scala)

I am looking for a clean object-orientated way to model the following (in Scala):
A person can be:
A manager at some firm
A mathematician
A world-class tennis player
A hobbyist programmer
A volunteer at a local school
A creative painter
This suggests that we introduce a Person super-class and sub-classes:
class Manager
class Mathematician
class TennisPlayer
class HobbyistProgrammer
class Volunteer
class Painter
The Manager class has methods such as: getSalary(), workLongHours(), findNewJob(), etc. The TennisPlayer class has methods such as: getWorldRanking(), playGame(), strainAnkle(), etc. And so on. In addition there are methods in class Person such as becomeSick(). A sick manager loses his job and tennis player stops playing in the season.
Futhermore the classes are immutable. That is, for instance strainAnkle() returns a new TennisPlayer that that has a strained ankle, but where all other properties remain the same.
The question is now: How do we model the fact that a person can be both a Manager and a TennisPlayer?
It's important that the solution preserves both immutability and type-safety.
We could implement classes such as:
ManagerAndMathematician
ManagerAndTennisPlayerAndPainter
ManagerAndPainter
but this leads to a combinatorial explosion of classes.
We could also use traits (with state), but then how do we implement methods such as findNewJob(), which needs to return a new person with the same traits mixed in, but with a new state of the Manager trait. Similarly, how can we implement methods such as becomeSick()?
Question: How would you implement this in a clean OO-fashion in Scala? Remember: Immutability and type-safety are a must.
This does not look to me like an ideal case for inheritance. Maybe you're trying to force things into an inheritance pattern because it seems awkward to handle composition with immutable values. Here's one of several ways to do it.
object Example {
abstract class Person(val name: String) {
def occupation: Occupation
implicit val self = this
abstract class Occupation(implicit val practitioner: Person) {
def title: String
def advanceCareer: Person
}
class Programmer extends Occupation {
def title = "Code Monkey"
def advanceCareer = practitioner
}
class Student extends Occupation {
def title = "Undecided"
def advanceCareer = new Person(practitioner.name) {
def occupation = new Programmer
}
}
}
def main(args: Array[String]) {
val p = new Person("John Doe") { def occupation = new Student }
val q = p.occupation.advanceCareer
val r = q.occupation.advanceCareer
println(p.name + " is a " + p.occupation.title)
println(q.name + " is a " + q.occupation.title)
println(r.name + " is a " + r.occupation.title)
println("I am myself: " + (r eq r.occupation.practitioner))
}
}
Let's try it out:
scala> Example.main(Array())
John Doe is a Undecided
John Doe is a Code Monkey
John Doe is a Code Monkey
I am myself: true
So this works in a somewhat useful way.
The trick here is that you create anonymous subclasses of your person each time an occupation (which is an inner class) decides to change things up. Its job is to create a new person with the new roles intact; this is helped out by the implicit val self = this and the implicit constructor on Occupation which helpfully automatically loads the correct instance of the person.
You will probably want a list of occupations, and thus will probably want helper methods that will regenerate the list of professions. Something like
object Example {
abstract class Person(val name: String) {
def occupations: List[Occupation]
implicit val self = this
def withOccupations(others: List[Person#Occupation]) = new Person(self.name) {
def occupations = others.collect {
case p: Person#Programmer => new Programmer
case s: Person#Pirate => new Pirate
}
}
abstract class Occupation(implicit val practitioner: Person) {
def title: String
def addCareer: Person
override def toString = title
}
class Programmer extends Occupation {
def title = "Code Monkey"
def addCareer: Person = withOccupations( this :: self.occupations )
}
class Pirate extends Occupation {
def title = "Sea Monkey"
def addCareer: Person = withOccupations( this :: self.occupations )
}
}
def main(args: Array[String]) {
val p = new Person("John Doe") { def occupations = Nil }
val q = (new p.Programmer).addCareer
val r = (new q.Pirate).addCareer
println(p.name + " has jobs " + p.occupations)
println(q.name + " has jobs " + q.occupations)
println(r.name + " has jobs " + r.occupations)
println("I am myself: " + (r eq r.occupations.head.practitioner))
}
}
A clean object-oriented way of solving this does not have to be Scala-specific. One could adhere to the general object-oriented design principle of favoring composition over inheritance and use something like Strategy pattern, which is a standard way of avoiding class explosion.
I think this can be solved in a manner similar to type-safe builders.
The basic idea is to represent "state" through type parameters, and use implicits to control methods. For example:
sealed trait TBoolean
final class TTrue extends TBoolean
final class TFalse extends TBoolean
class Person[IsManager <: TBoolean, IsTennisPlayer <: TBoolean, IsSick <: TBoolean] private (val name: String) {
// Factories
def becomeSick = new Person[TFalse, IsTennisPlayer, TTrue](name)
def getBetter = new Person[IsManager, IsTennisPlayer, TFalse](name)
def getManagerJob(initialSalary: Int)(implicit restriction: IsSick =:= TFalse) = new Person[TTrue, IsTennisPlayer, IsSick](name) {
protected override val salary = initialSalary
}
def learnTennis = new Person[IsManager, TTrue, IsSick](name)
// Other methods
def playGame(implicit restriction: IsTennisPlayer =:= TTrue) { println("Playing game") }
def playSeason(implicit restriction1: IsSick =:= TFalse, restriction2: IsTennisPlayer =:= TTrue) { println("Playing season") }
def getSalary(implicit restriction: IsManager =:= TTrue) = salary
// Other stuff
protected val salary = 0
}
object Person {
def apply(name: String) = new Person[TFalse, TFalse, TFalse](name)
}
It can get very wordy, and if things get complex enough, you may need something like an HList. Here's another implementation, that separates concerns better:
class Person[IsManager <: TBoolean, IsTennisPlayer <: TBoolean, IsSick <: TBoolean] private (val name: String) {
// Factories
def becomeSick = new Person[TFalse, IsTennisPlayer, TTrue](name)
def getBetter = new Person[IsManager, IsTennisPlayer, TFalse](name)
def getManagerJob(initialSalary: Int)(implicit restriction: IsSick =:= TFalse) = new Person[TTrue, IsTennisPlayer, IsSick](name) {
protected override val salary = initialSalary
}
def learnTennis = new Person[IsManager, TTrue, IsSick](name)
// Other stuff
protected val salary = 0
}
object Person {
def apply(name: String) = new Person[TFalse, TFalse, TFalse](name)
// Helper types
type PTennisPlayer[IsSick <: TBoolean] = Person[_, TTrue, IsSick]
type PManager = Person[TTrue, _, _]
// Implicit conversions
implicit def toTennisPlayer[IsSick <: TBoolean](person: PTennisPlayer[IsSick]) = new TennisPlayer[IsSick]
implicit def toManager(person: PManager) = new Manager(person.salary)
}
class TennisPlayer[IsSick <: TBoolean] {
def playGame { println("Playing Game") }
def playSeason(implicit restriction: IsSick =:= TFalse) { println("Playing Season") }
}
class Manager(salary: Int) {
def getSalary = salary
}
To get better error messages you should use specialized versions of TBoolean (ie, HasManagerJob, PlaysTennis, etc), and the annotation implicitNotFound to go with it.