Override an abstract type element in a pattern.

Suppose we want to determine how to accumulate results from some data:

case class Data(x: Int, y: Int) 

We define a trait for this:

 trait Accumulator { type R def add(acc: R, d: Data): R def zero: R } 

And a simple implementation:

 trait XAccumulator extends Accumulator { type R = Int def add(acc: Int, d: Data) = acc + dx def zero = 0 } 

I would like to use the stackable-trait pattern to use several of these simple batteries:

 trait TraceYAccumulator extends Accumulator { abstract override type R = (Seq[Int], super.R) // fails: // `abstract override' modifier not allowed for type members def add(acc: R, d: Data) = { val r = super.add(acc._2, d) (acc._1 :+ dy, r) } def zero = (Seq.empty[Int], super.zero) } 

Apparently, I am not allowed to redefine an element of an abstract type. How to change the result type of overridden methods using the template of stackable attributes?

My second approach was to use type parameters:

 trait Accumulator[R] { def add(acc: R, d: Data): R def zero: R } trait XAccumulator extends Accumulator[Int] { def add(acc: Int, d: Data) = acc + dx def zero = 0 } 

But now it's getting really weird:

 trait TraceYAccumulator[T] extends Accumulator[(Seq[Int], T)] { this: Accumulator[T] => def add(acc: (Seq[Int], T), d: Data): (Seq[Int], T) = { val r = this.add(acc._2, d) // fails: overloaded method value add with alternatives: // (acc: (Seq[Int], T),d: Data)(Seq[Int], T) <and> // (acc: _14695,d: Data)_14695 cannot be applied to (T, Data) (acc._1 :+ dy, r) } def zero: (Seq[Int], T) = (Seq.empty[Int], this.zero) } 

Since the superclass class and the mixed class have the same method names (obviously), we cannot refer to the correct methods. My only use case for composition?

How can I add such operations?

+4
source share
1 answer

The first approach has a fundamental theoretical problem:

Suppose we are allowed to write these traits. Then consider the following:

 val acc = new XAccumulator with TraceYAccumulator val xacc = acc: XAccumulator 

Since xacc is an XAccumulator , we know that xR =:= Int . By email Oh.

The second approach has an implementation problem: you cannot inherit from different instances of the same trait.

 illegal inheritance; anonymous class $anon inherits different type instances of trait Accumulator: Accumulator[Int] and Accumulator[(Seq[Int], Int)] 

Therefore, the composition (or maybe some cool hacker) seems to be the only option.

+1
source

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


All Articles