Reputation: 1665
I'm wondering if it is possible to mixin a Scala trait with an instance to make an anonymous instance.
basically I would to do something like that
trait Duck {
def walk : Unit
}
def learnToDuckWalk[A](a : A) : A with Duck = a with Duck {
def walk = print("flic flak floc")
}
The idea is to make a new type without having to define a all new class that extends 2 types. Because define a new class for each type could lead to exponential number of class, growing each time we add a new Trait to mixin.
I saw few things that look like this in ZIO.Has but I'm wondering if it is doable with pure Scala 2 or even with Scala 3.
Upvotes: 0
Views: 508
Reputation: 9698
Do you really need a generic parameter A
, or was that just for example sake? If you had a concrete type instead of A
, then you could just create an instance that mixes in both traits:
trait Duck {
def walk: Unit
}
trait Goose {
def run: Unit
}
def learnToDuckWalk: Goose with Duck = new Goose with Duck {
def run = println("tip tap top")
def walk = println("flic flak floc")
}
learnToDuckWalk.walk
learnToDuckWalk.run
However, having a generic A
and "bolting-on" some extra traits is not really a good design, even if you managed to implement it (e.g. using reflection).
A better approach would be, instead of saying "I have an A
that is mixed in with Duck
", to say "I have an A
that has a Duck
type class instance".
trait Duck [A]{
def walk : Unit
}
object Duck {
implicit val duckString = new Duck[String] {
def walk = print("Stringy flic flak floc")
}
implicit val duckInt = new Duck[Int] {
def walk = print("Inty flic flak floc")
}
...
implicit def duckA[A] = new Duck[A] {
def walk = print("Generic flic flak floc")
}
}
This way you can provide type class instances for any type you want, and you can have them behave differently depending on the actual type (see how walk
prints a different message fo each type).
Then your use-site can look like this:
import Duck._
def learnToDuckWalk[A : Duck](a : A) = {
val aDuck = implicitly[Duck[A]]
aDuck.walk // prints Stringy flic flak floc
}
learnToDuckWalk("Some string")
Important part here is the [A : Duck]
type, which means "any A
for which a Duck
type class instance exists".
Upvotes: 1