Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala passing in traits as parameters to be mixed in

Tags:

scala

traits

I have (for lack of a better term) a factory method that encapsulates constructing an object:

def createMyObject = new SomeClass(a, b, c, d)

Now, depending on the context, I will need to mix in one or more traits into SomeClass:

new SomeClass with Mixin1

or

new SomeClass with Mixin2 with Mixin3

Instead of creating multiple separate factory methods for each "type" of instantiation, how can I pass in the traits to be mixed in so that it can be done with a single method? Or perhaps there is a good pattern for this that is structured differently?

I'd like to maintain the encapsulation so I'd rather not have each consumer just create the class on its own.

like image 842
oym Avatar asked Oct 21 '25 14:10

oym


1 Answers

If you need only mixins without method overriding, you can just use type classes:

trait Marker
class C[+T <: Marker] { def b = 1 }

trait Marker1 extends Marker
implicit class I1[T <: Marker1](c: C[T]) {def a = 6 + c.b}

trait Marker2 extends Marker
implicit class I2[T <: Marker2](c: C[T]) {def a = 5 + c.b}

trait Marker3 extends Marker
implicit class I3[T <: Marker3](c: C[T]) {def k = 100}

trait Marker4 extends Marker3
implicit class I4[T <: Marker4](c: C[T]) {def z = c.k + 100} //marker3's `k` is visible here

scala> def create[T <: Marker] = new C[T]
create: [T <: Marker]=> C[T]


scala> val o = create[Marker1 with Marker3]
o: C[Marker1 with Marker3] = C@51607207

scala> o.a
res56: Int = 7

scala> o.k
res57: Int = 100

scala> create[Marker4].z
res85: Int = 200

But it won't work for create[Marker1 with Marker2].a (ambiguous implicits), so no linearization here. But if you want to just mix-in some methods (like in javascript's prototypes) and maybe inject something - seems to be fine. You can also combine it with traditional linearized mix-in by adding some traits to C, I1, I2, etc.

like image 168
dk14 Avatar answered Oct 23 '25 05:10

dk14



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!