3

I'm currently working on a A* implementation in Scala. To accomplish a clean structure I would like to use a nested case class structure which implements a self-bounded trait. However, I experience some issues when implementing this in the Scala IDE. The following code will not compile:

trait A[T <: A[T]]

class B {

    case class C(int: Int) extends A[C] // A[this.C] won't work either

    def make = C(5)

}

object D {

    def foo[T <: A[T]](some: T) = {}

    val c = new B().make

    foo(c) // this does not compile

}

Is there any way I can make this structure work?

1

1 Answer 1

5

Not sure why you want this, but here's why it won't work as is:

The type of D.c is B#C. It is a path-dependent type where we don't know what instance of B it belongs to. However, C extends A[C], which is the already the same as saying A[this.C] in that context, which is bound to a specific instance of B. foo sees the type parameter T as B#C, which is not the same as b.C for some b.

You have two options to make this compile.

Relax the constraints of A to B#C:

trait A[T <: A[T]]

class B {

    case class C(int: Int) extends A[B#C]

    def make = C(5)

}

object D {

    def foo[T <: A[T]](some: A[T]) = {}

    val c = new B().make

    foo(c)

}

Or handle the path-dependent type, so that c has type b.C:

trait A[T <: A[T]]

class B {

    case class C(int: Int) extends A[C]

    def make = C(5)

}

object D {

    def foo[T <: A[T]](some: A[T]) = {}

    val b = new B
    val c: b.C = b.make

    foo(c)

}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! This explained a lot!
The explicit type on c in the last example isn't actually necessary, I found. I would love an explanation for why introducing the intermediate val b changes the inferred type of c. I get that there is no name for the intermediate value without b but not how that matters to the inference.
I don't think there is a spec for type inference rules, so I'm at a loss there. I just don't think the type inferencer is smart enough in this case to do it all in one statement--similar to why you need to curry arguments like def f(b: B)(c: b.C)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.