Lasf
Lasf

Reputation: 2582

How to override value when value types have a different number of type parameters?

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.

Upvotes: 3

Views: 850

Answers (2)

chengpohi
chengpohi

Reputation: 14227

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.

Upvotes: 1

Andrey Tyukin
Andrey Tyukin

Reputation: 44937

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)

Upvotes: 2

Related Questions