Avoid name collision with cake pattern

I am currently using the Cake pattern to implement some optimization algorithms. I often run into name collision issues. For instance:

trait Add[T] { this: Foo[T] => def constant: T def plus( t1: T, t2: T ): T def add( t: T ) = plus( t, constant ) } trait Mul[T] { this: Bar[T] => def constant: T def times( t1: T, t2: T ): T def mul( t: T ) = times( t, constant ) } trait Operations[T] { this: Add[T] with Mul[T] => def neg( t: T ): T } 

Here, constant defined both in Add and in Mul , but their values ​​can be different. I could prefix the name with the name of the attribute, but I find it ugly and fragile ( def mulConstant: T ). Is there a better way to do this?

+6
source share
2 answers

To my best knowledge, a traditional pie template usually includes 1 layer of nesting attributes to group operations together. Then the outer layer declares the actual "service" (here: "Add, Mul, Operations") without defining it.

 trait AddComponent[T] { this: FooComponent[T] => def addition: Add trait Add { def constant: T def plus( t1: T, t2: T ): T def add( t: T ) = plus( t, constant ) } } trait MulComponent[T] { this: BarComponent[T] => def multiplication: Mul trait Mul { def constant: T def times( t1: T, t2: T ): T def mul( t: T ) = times( t, constant ) } } trait OperationsComponent[T] { this: Add[T] with Mul[T] => def operations: Operations trait Operations { def neg( t: T ): T } } 

Then, when mixing the signs "... Component" are interdependently linked:

 trait IntOperations extends Operation[Int] { class IntAdd extends Add { ... } class IntMul extends Mul { ... } } class MyFooBar extends FooComponent[Int] with BarComponent[Int] with IntOperations { lazy val addition = new IntAdd lazy val multiplication = new IntMul lazy val foo = ... lazy val bar = ... } 

This solves your specific problem with names, but name conflicts (from the "service" definitions) remain the problem of the traditional cake template. There is a blog post by Daniel Spivak demonstrating how this can be resolved in general, but the solution comes with its own set of (huge) trade-offs (see this talk ).

Hope this helps.

PS instead of type parameters it would be better to use abstract types here.

+7
source

It may be a little unfashionable to say, and this is not a direct answer to your question, but isn’t it easier to just inject dependencies into the constructors? Each collaborator has their own namespace, so a collision never occurs. And there is no problem with the public class api. However, it is still difficult to mix DI and cake samples.

0
source

Source: https://habr.com/ru/post/944866/


All Articles