is not a legal prefix for a constructor when creating a nested class

Viewed 241

I'm trying to create an instance of a Java nested class but when compile I see is not a legal prefix for a constructor.

I have a Java library with classes A1 and A2 defined like this

public class A1 {
  public class A2 {
    public A2() {...}
  }
  public A2 getA2() {
    return new A2();
  }
}

I'm trying to extend this class in Scala and doing something like this

class B(...) extends A1(...) {
  override def getA2() = {
    new A1#A2()
  }
}

When I compile I get this error

 A1 is not a legal prefix for a constructor
[error]     new A1#A2()
[error]                 ^
[error] one error found
[error] (connector/test:compileIncremental) Compilation failed
[error] Total time: 2 s, completed May 21, 2020 11:34:44 PM
[IJ]> 

This seems to be a known compiler issue (see github issue), the workaround won't work here as I cannot change the library code.

1 Answers

This isn't an instance of that issue. Trying to say new A1#A2 is like trying to say def mk[T]() = new T. You're missing out on essential information. For which A1 do you want to make an A2? In your code, you just want to instantiate new this.A2(). You can omit the this, as usual: new A2()

class B(...) extends A1(...) {
  override def getA2() = new A2()
}

The reason new A1#A2() fails is because each A1 has its own A2. For

val a: A1 = ???
val b: A1 = ???

a.A2 and b.A2 are different types. A1#A2 is not a name for "the 'underlying' A2 class that all A1s share," because in Scala there is no such thing (the fact that Java's A1.A2 does work like that might be seen as a leaky abstraction on Java's part). A1#A2 is actually more like a wildcard type: A2 for some A1. Just like you can't say new Array[_](5) (what element type do you want?), you can't say new A1#A2() (which A1 do you want?).

Related