Type equivalence issue when using dependent method types and the type projections

230 views Asked by At

I'm trying the following with Scala 2.10.0-M1:

trait Container {
  type X
}

class Test[C <: Container](val c: C) {
  def foo(x: c.X): C#X = x // this compiles fine
  def bar(x: C#X): c.X = x // this does not compile
}

The problem is the same when using this form:

def bar[C <: Container](c: C)(x: C#X): c.X = x

I don't really see why foo compiles while bar does not.

I believe that c.X and C#X should be the same here.

Also, I don't understand the error message:

[error]  found   : x.type (with underlying type C#X)
[error]  required: Test.this.c.X
[error]  possible cause: missing arguments for method or constructor
[error]   def bar(x: C#X): c.X = x // this does not compile

Any idea?

3

There are 3 answers

0
Rex Kerr On BEST ANSWER

C#X means an X from any C. c.X means an X from your particular C, namely c. The latter is much more specific!

For example, if X is a bill and c is a particular customer, c.X means that the method only accepts bills from (for, presumably) customer c. C#X means it accepts any bill from any customer. If you want to ensure that customers only get charged with their own bills (at least by default), the former is what you want.

0
Daniel C. Sobral On

c.X and C#X are definitely not the same -- if they were, why would both exist?

Consider the case where you have a and b, different instances of C. By definition, a.X and b.X are different, but both are C#X.

0
Miles Sabin On

@Rex has given a good explanation of what's wrong. Here's how you might fix it ...

If it's reasonable to be able to return x as a result of type c.X (ie. a value of the X type of the particular c passed as an argument, then you can tighten it's type as an argument,

def bar[C <: Container](c: C)(x: c.X): c.X = x

Now bar will only accept values of type X which are relative to the specific value c. If that doesn't work for you at the call sites of bar, then you will need to rework your design.