3

Why does this happily compile,

class Foo[T]

class DerivedFoo[T] extends Foo[T]

class Bar(val foo: Foo[_])

class DerivedBar(override val foo: DerivedFoo[_]) extends Bar(foo)

while this does not?

class OtherDerivedFoo[T, U] extends Foo[T]

class OtherDerivedBar(override val foo: OtherDerivedFoo[_, _]) extends Bar(foo)
//error: value foo overrides nothing

Is there a workaround? Thanks.

Lasf
  • 2,536
  • 1
  • 16
  • 35
  • FWIW, Andrey Tyukin's solution translated using my framing is `class OtherDerivedBar(override val foo: (Foo[T] with OtherDerivedFoo[T, _]) forSome { type T } ) extends Bar(foo)` – Lasf Mar 12 '18 at 02:12

2 Answers2

2

Workaround:

Currently, I cannot quite articulate why it works, but it works:

import scala.language.existentials
class DerivedFoo2[T, U] extends Foo[T]
class DerivedBar2(
  override val foo: (Foo[X] with DerivedFoo2[X, _]) forSome { type X }
) extends Bar(foo)

(I've replaced OtherDerivedFoo by DerivedFoo2, see renaming notice below)

Renaming

I have renamed the classes as follows, to emphasize the parallels between the two cases, and to make the code of the workaround shorter:

Assuming that you have

class Foo[T]
class Bar(val foo: Foo[_])

This compiles:

class DerivedFoo1[T] extends Foo[T]
class DerivedBar1(override val foo: DerivedFoo1[_])    extends Bar(foo)

But this doesn't:

class DerivedFoo2[T, U] extends Foo[T]
class DerivedBar2(override val foo: DerivedFoo2[_, _]) extends Bar(foo)
Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • Thanks. Would be interesting to know why this occurs and why this solution works! – Lasf Mar 12 '18 at 02:10
  • @Lasf Why the workaround works is clear, what's not clear why your second case doesn't... I personally don't find my own answer entirely satisfactory, it's more of a quick-fix. If someone shows up who can actually *explain* the behavior, don't hesitate to unaccept and accept the more detailed answer. Alternatively, if you have good memory or the good habit of not leaving any of your questions unsolved, just unaccept my answer for now, it might get some more attention on Monday morning in this way. And maybe tag it as `scala-compiler`? I don't know. – Andrey Tyukin Mar 12 '18 at 02:17
  • 1
    Good call. Unaccepted for now... if nothing better comes along in a few days I'll re-accept. Thanks again. – Lasf Mar 12 '18 at 02:33
1

Seems this is a Scala compiler bug, Scala compiler will check whether subclass's override variable match the superclass's variable type, by checkOverride method,

For DerivedBar & OtherDerivedBar it's checking the Existential types(thats the wildcard _) whether matches with Bar.foo type by matchesType, but for OtherDerivedBar it has 2 ExistentialType, so it will fail on sameLength compare method, this will cause type mismatch.

As Andrey's solution, actually the compiler will compile OtherDerivedBar to [ClassArgsType, ExistentialType], this will pass on the sameLength compare, so no compile error will thrown.

but actually even OtherDerivedBar has 2 ExistentialType it also should be legal override type for Foo, since:

type F = OtherDerivedFoo[_, _]

class OtherDerivedBar(override val foo: F) extends Bar(foo)

it's also compiled.

chengpohi
  • 14,064
  • 1
  • 24
  • 42
  • Many thanks. Now I'm not sure whether to give the checkmark to Andrey (solution) or you (explanation) :/ – Lasf Mar 13 '18 at 10:41