I am trying to parameterize some methods with very general type parameters.
As an example, in the REPL I first define:
trait Term
case class FunctionalTerm[+T <: Term](t: T) extends Term
Intuitively, the following method takes a Term and a FunctionalTerm, and returns something with type the least upper bound of the type of term passed and the argument type of the FunctionalTerm:
def ex1[T1 <: Term, T3 <: X, FunctionalTerm[T1] <: X, X <: R, R <: Term](t1: FunctionalTerm[T1], s: T3): R = sys.error("TODO")
So far so good in the REPL.
Then I define ex2
as a convenience function that performs the same operation as ex1
, but with the input arguments swapped:
def ex2[T2 <: Term, T3 <: X, FunctionalTerm[T2] <: X, X <: R, R <: Term](s: T3, t2: FunctionalTerm[T2]): R = ex1(t2,s)
Attempting to define ex2
in the REPL gives the following error:
error: inferred type arguments [T2,T3,FunctionalTerm,T3,T3] do not conform to method ex1's type parameter bounds [T1 <: Term,T3 <: X,FunctionalTerm[T1] <: X,X <: R,R <: Term]
ex1(t2,s)
^
error: type mismatch;
found : FunctionalTerm[T2]
required: FunctionalTerm[T1]
ex1(t2,s)
^
error: type mismatch;
found : T3(in method ex2)
required: T3(in method ex1)
ex1(t2,s)
^
error: type mismatch;
found : R(in method ex1)
required: R(in method ex2)
ex1(t2,s)
^
I have spent about two days trying to figure out a solution, and am now totally stuck. I cannot find anything more on Google.
Since the type argument list of ex2
is the same as that of ex1
but with T1
and T2
swapped, I don't understand is wrong, or how to fix it.
Any help would be hugely appreciated!
Update
Least upper bounds were a red herring. The example can be distilled further.
The following two functions can be defined in the REPL without error:
def ex1[T1 <: Term, FunctionalTerm[T1] <: Term](t1: FunctionalTerm[T1]): Term = sys.error("TODO: ex1")
def ex2[T2 <: Term, FunctionalTerm[T2] <: Term](t2: FunctionalTerm[T2]): Term = ex1(t2)
Introducing the extra parameter X
seems to cause the problem. I can define the following in the REPL:
def ex3[T1 <: Term, FunctionalTerm[T1] <: X, X <: Term](t1: FunctionalTerm[T1]): Term = sys.error("TODO: ex3")
But attempting to subsequently define:
def ex4[T2 <: Term, FunctionalTerm[T2] <: X, X <: Term](t2: FunctionalTerm[T2]): Term = ex3(t2)
gives the error:
error: inferred type arguments [T2,FunctionalTerm,Nothing] do not conform to method ex3's type parameter bounds [T1 <: Term,FunctionalTerm[T1] <: X,X <: Term]
def ex4[T2 <: Term, FunctionalTerm[T2] <: X, X <: Term](t2: FunctionalTerm[T2]): Term = ex3(t2)
^
error: type mismatch;
found : FunctionalTerm[T2]
required: FunctionalTerm[T1]
def ex4[T2 <: Term, FunctionalTerm[T2] <: X, X <: Term](t2: FunctionalTerm[T2]): Term = ex3(t2)
^
So, I guess the question becomes: Why does the parameter X
unused in the signature have this effect?
I'm not sure whether or not you're experiencing a bug, but I am pretty sure you're making your life a lot more difficult that it needs to be. You can rely on covariance and unification to do all the hard work for you,
Note the inferred result type (which is equivalent to the
R
of your original more complex definition) ... it'sA
which is the LUB ofB
andC
.Now the flipped version is trivial and Just Works,