6

I cannot write the following F-bounded polymorphism in Scala. Why?

trait X[T <: X[T]]
object Y extends X[Y]

How can I express this and make it compile?

Mikaël Mayer
  • 10,425
  • 6
  • 64
  • 101

2 Answers2

7

It really seems like you ought to be able to write,

trait X[T <: X[T]]
object Y extends X[Y.type]

however, if you try that the compiler will give you an unhelpful (and I think spurious) error,

scala> object Y extends X[Y.type]
<console>:16: error: illegal cyclic reference involving object Y
       object Y extends X[Y.type]

I say "spurious" because we can construct an equivalent object with a little bit of additional infrastructure,

trait X[T <: X[T]]

trait Fix { type Ytype >: Y.type <: Y.type; object Y extends X[Ytype] }
object Fix extends Fix { type Ytype = Y.type }
import Fix.Y

If you wanted to experiment with this in real code, using a package object in place of object Fix would make this idiom a little more usable.

Miles Sabin
  • 23,015
  • 6
  • 61
  • 95
  • Do you think this is a compiler bug or is it an oversight in the spec? Or maybe there is some subtlety we're not seeing which makes the error necessary? – Jörg W Mittag Aug 25 '15 at 21:47
  • 4
    A conversation with @retronym on [scala/scala](https://gitter.im/scala/scala?at=55dc7303fcfd5a7865af45d4) suggests it's a bug. And it [works as expected on Dotty](https://gitter.im/lampepfl/dotty?at=55dc95a3a6bcd8894068e278). – Miles Sabin Aug 26 '15 at 07:44
1

Change it to :

  trait Y extends X[Y]

object is not a type in Scala, but the so called companion object. By defining object Y, you can't express that it should extend trait T[Y], since that second Y refers to a type Y that hasn't been defined. You can however do the following:

trait Y extends X[Y]          //If you try this on the REPL, do :paste before
object Y extends X[Y]

In this case the object Y extends X[Y] where the second Y is the trait you just define, make sure you keep this in mind.

Chirlo
  • 5,989
  • 1
  • 29
  • 45
  • I would like Y to be instanciated only once and access its unique instance, that's why I need an object. – Mikaël Mayer Aug 25 '15 at 12:34
  • Then you can make the constructor private with `class Y private() extends X[Y]` and just make that one instance publicly available. – Chirlo Aug 25 '15 at 12:41