Ok, so I have this wonderfully simple setup:
trait Sys[S <: Sys[S]] trait Elem[S <: Sys[S]] trait AttrElem[S <: Sys[S]] { type E <: Elem[S] def attributes: Any def element: E } And a factory:
object Factory { def apply[S <: Sys[S], E1 <: Elem[S]]( elem: E1): AttrElem[S] { type E = E1 } = new Impl(elem) private class Impl[S <: Sys[S], E1 <: Elem[S]](val element: E1) extends AttrElem[S] { type E = E1 def attributes = 1234 } } Now in practice the f*** Scala type inference breaks down:
def test[S <: Sys[S]](elem: Elem[S]): Unit = { Factory(elem) } <console>:62: error: inferred type arguments [Nothing,Elem[S]] do not conform to method apply's type parameter bounds [S <: Sys[S],E1 <: Elem[S]] Factory(elem) ^ So my next attempt is existential types:
object Factory { def apply[S <: Sys[S], E1[~] <: Elem[~] forSome { type ~ <: Sys[~] }]( elem: E1[S]): AttrElem[S] { type E = E1[S] } = new Impl(elem) private class Impl[S <: Sys[S], E1[~] <: Elem[~] forSome { type ~ <: Sys[~] }]( val element: E1[S]) extends AttrElem[S] { type E = E1[S] def attributes = 1234 } } This gives me this following lovely message:
<console>:62: error: inferred kinds of the type arguments (S,E1[S]) do not conform to the expected kinds of the type parameters (type S,type E1) in class Impl. E1[S]'s type parameters do not match type E1's expected parameters: type E1 has one type parameter, but type E1 (in class Impl) has one elem: E1[S]): AttrElem[S] { type E = E1[S] } = new Impl(elem) ^ "type E1 has one type parameter, but type E1 has one" -- huh?
Question: How can I define the factory's apply method to infer the types?
f***an abbreviation forf-bounded polymorphic?Factory(elem)whenelemis fully known, a sub-type ofElem[S]. Without having to typeFactory[S, SomeSubtypeOfElem[S]](elem). In other words, I want to use the advertised feature of type-inference