Skip to content

Illegal inheritance with inner class inheritance #8830

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
scabug opened this issue Aug 28, 2014 · 9 comments
Closed

Illegal inheritance with inner class inheritance #8830

scabug opened this issue Aug 28, 2014 · 9 comments
Assignees

Comments

@scabug
Copy link

scabug commented Aug 28, 2014

This problem can be a blocker when working with inner class inheritance hierarchies.

Reproduce code

trait A{ trait Foo }
trait B extends A{ trait Foo extends super.Foo }
val b: B = new B{}
val a: A = b
new b.Foo with a.Foo

Expected result
compiles fine

Actual result

error: illegal inheritance;
 <$anon: b.Foo with a.Foo> inherits different type instances of trait Foo:
a.Foo and b.Foo
              new b.Foo with a.Foo
                  ^

Note that this happens even if the inner child class does not have the same name as the inner parent, but this fact forces having to upcast to B in order to access the inner parent.

In Slick it prevents an external user to us RelationalProfile's SimpleQL class with JdbcProfile's Implicits class.

@scabug
Copy link
Author

scabug commented Aug 28, 2014

Imported From: https://issues.scala-lang.org/browse/SI-8830?orig=1
Reporter: @cvogt
Affected Versions: 2.10.4, 2.11.2

@scabug
Copy link
Author

scabug commented Sep 1, 2014

@retronym said (edited on Sep 1, 2014 3:08:16 AM UTC):
What you are asking for is unsound. Here's why:

class Box[A](var value: A)
class A { class Foo extends Box[A.this.type](A.this) }
class B extends A { class Bar extends Foo }
object Test extends App {
  val b: B = new B
  val a: A = new A // you wrote `b` here, but I changed to `new A` so as to demonstrate the unsoundness that this restriction prevents.
  val mix: b.Bar with a.Foo = new b.Bar().asInstanceOf[b.Bar with a.Foo] // new b.Bar with a.Foo {}
  (mix: b.Bar).value = b
  val a1: a.type = (mix: a.Foo).value
  assert(a1 == a) // fails
}

@scabug scabug closed this as completed Sep 1, 2014
@scabug
Copy link
Author

scabug commented Sep 1, 2014

@cvogt said:
@retronym Ah right. val a: A = b looses the path-information about the specific b.

Ok, then back to the original question that got me here: If I have a specific b, how can I access it's A-parent's Foo class, in case it is shadowed by it's B-parent's Foo class like in my original example?

@scabug
Copy link
Author

scabug commented Sep 2, 2014

@retronym said:
How about:

trait A{ trait Foo; type FooA = Foo }
trait B extends A{ trait Foo extends super.Foo }

Generally I would recommend against defining an inner classes with the same name as one in a parent. Use type aliases instead, in the style of scala-reflect. Following that discipline avoids unsoundness traps like #6161.

@scabug
Copy link
Author

scabug commented Sep 2, 2014

@cvogt said:
What if you are not writing the classes? You just find them in a library and can't change their code. I am trying to write an external extension for Slick 2.1. We could change the shadowing for Slick 2.2, but 2.1 is shipped.

/cc @szeiger

@scabug
Copy link
Author

scabug commented Sep 2, 2014

@retronym said:
I'm still not quite following the motivation.

In your original code:

trait A{ trait Foo }
trait B extends A{ trait Foo extends super.Foo }
val b: B = new B{}
val a: A = b
new b.Foo with a.Foo

Why didn't you just write:

new b.Foo

given that B#Foo already extends A#Foo?

@scabug
Copy link
Author

scabug commented Sep 2, 2014

@cvogt said (edited on Sep 2, 2014 12:37:44 AM UTC):
The motivation: I want everything from A#Foo, but not the stuff added in B#Foo. B#Foo adds some implicits, which I would like to exclude.

@scabug
Copy link
Author

scabug commented Sep 2, 2014

@retronym said:
IIUC, the only approach you could try would be to use more inheritance:

trait A{ trait Foo }
trait B extends A {
  trait Foo extends super.Foo { def xxx = 0 }
}

// extension
trait C extends B with A {
  type AFoo = super[A].Foo
}

object Test extends App {
  val c = new C {}
  val afoo = new c.AFoo {}
  afoo.xxx // does not compile
}

@scabug
Copy link
Author

scabug commented Sep 3, 2014

@cvogt said:
So no external way. Thx.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants