Existential type or type parameter bound failure

229 views Asked by At

I have an F-bounded type Sys:

trait Sys[S <: Sys[S]]

And some trait which take it as type parameter:

trait Foo[S <: Sys[S]]

Suppose I have a method to be invoked with a Foo:

def invoke[S <: Sys[S]](foo: Foo[S]) = ()

Suppose I have a model update type, and a sub-type which carries a Foo:

sealed trait Update
case class Opened[S <: Sys[S]](foo: Foo[S]) extends Update

A helper function to register a model observer:

def observe(pf: PartialFunction[Update, Unit]) = ()

Now the following fails:

observe {
  case Opened(foo) => invoke(foo)
}

with

<console>:16: error: inferred type arguments [Any] do not conform to method invoke's
                     type parameter bounds [S <: Sys[S]]
                case Opened(foo) => invoke(foo)
                                    ^

How can I fix the partial function, if Sys, Foo, invoke, Update, Opened and observe are given. It is allowed to add a value or type member to Foo.

2

There are 2 answers

0
0__ On BEST ANSWER

A possible solution is casting:

observe {
  case Opened(foo) => invoke(foo.asInstanceOf[Foo[~] forSome { type ~ <: Sys[~] }])
}

Obviously this is horrible and not the preferred solution, so I am waiting for other answers.

1
Yuriy On

How about move type parameter for Foo trait to type variable:

trait Sys[S <: Sys[S]]
trait Foo { type S <: Sys[S] }

sealed trait Update
case class Opened(foo: Foo) extends Update

def invoke(foo: Foo) = ()
def observe(pf: PartialFunction[Update, Unit]) = ()

observe {
  case Opened(foo) => invoke(foo)
}

Update:

You are absolutely right. And for all new type substitution you need to define alias for move type parameter to body.

Type alias example:

trait Sys[S <: Sys[S]]
class A extends Sys[A]
class B extends Sys[B]

trait Foo { type S <: Sys[S] }
trait Boo { type S <: Sys[S] } 

object module_A{
  type Foo = com.company.Foo { type S <: A }
  type Boo = com.company.Boo { type S <: A }
}

def invoke(foo: module_A.Foo, boo: module_A.Boo) = ()