Understanding "Type Argument Arguments Does Not Meet Type Parameter Constraints" in Scala

I do not understand why I get "inferred type arguments that do not match the boundaries of the type parameters". Firstly, I defined a CS attribute that can be implemented by several classes (for example, CS01 and CS02):

trait CS[+T <: CS[T]] { this: T => def add: T def remove: T } class CS01 extends CS[CS01] { def add: CS01 = new CS01 def remove: CS01 = new CS01 } class CS02 extends CS[CS02] { def add: CS02 = new CS02 def remove: CS02 = new CS02 } 

The idea is to save the implemented type when calling add or remove on CS01 and CS02. Secondly, I would like to define the operations that can be performed on all classes corresponding to CS characteristics. Then I defined the sign of Exec (with two very simple examples of the classes Exec01 and Exec02 mixin Exec ):

 trait Exec { def exec[U <: CS[U]](x: U): U } class Exec01 extends Exec { def exec[U <: CS[U]](x: U): U = x.add } class Exec02 extends Exec { def exec[U <: CS[U]](x: U): U = x.remove } 

Once again, I need to save an implemented class type that mixes the CS trait. This is why exec is parameterized using [U <: CS[U]] .

Finally, I want any CS include operations in it to mix the Executable attribute, which allows you to perform the operation following the Exec attribute:

 trait Executable[T <: CS[T]] { this: T => def execute(e: Exec): T = e.exec(this) } 

However, when I try to compile, I get the following error:

 error: inferred type arguments [this.Executable[T] with T] do not conform to method exec type parameter bounds [U <: this.CS[U]] def execute(e: Exec): T = e.exec(this) ^ 

I do not quite understand, because any classes that mix Executable must have type T with the restriction of mixing the CS attribute from abroad in trait Executable[T <: CS[T]] . So, why does this not match a parameter of type bound U <: CS[U] ?

+7
source share
2 answers

It works if you explicitly specify the type parameter for exec:

 def execute(e: Exec): T = e.exec[T](this) 

This seems to be a limitation in type inference.

+4
source

Disclaimer: There is no scala guru here, I study him when I write this.

First, simplify the example.

 scala> trait Moo[+X <: Moo[X]] defined trait Moo scala> class Foo extends Moo[Foo] defined class Foo scala> def foobar[U <: Moo[U]](x: U) = x foobar: [U <: Moo[U]](x: U)U scala> foobar(new Foo) res0: Foo = Foo@191275b scala> class Bar extends Foo defined class Bar scala> foobar(new Bar) <console>:12: error: inferred type arguments [Bar] do not conform to method foobar type parameter bounds [U <: Moo[U]] foobar(new Bar) ^ scala> 

foobar accepts the argument Foo , but rejects Bar , which only extends Foo . What for? foobar is the generic, parameterizable type of its argument. This imposes a restriction on this type. The inferencer type will not check every ancestor type argument, hoping to find one that satisfies the evaluation.

So how do you bind an ancestor type? One of the methods is with existential types.

 scala> def foobar[V <: Moo[U] forSome {type U}](x: V) = x foobar: [U <: Moo[_], V <: U](x: V)V scala> foobar(new Foo) res3: Foo = Foo@1154718 scala> foobar(new Bar) res4: Bar = Bar@5a7ff7 scala> 
+2
source

All Articles