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
Qualifiers when overriding Java methods #12349
Comments
The following modifications seem to be optimal for // compiler/scala/tools/nsc/typechecker/RefChecks.scala
/* ... */
def isOverrideAccessOK = member.isPublic || { // member is public, definitely same or relaxed access
(!other.isProtected || member.isProtected) && // if o is protected, so is m
((!isRootOrNone(ob) && ob.hasTransOwner(mb)) || // m relaxes o's access boundary
other.isJavaDefined) // overriding a protected java member, see #3946
}
/* ... */ Fix it like this(Add // compiler/scala/tools/nsc/typechecker/RefChecks.scala
/* ... */
def isOverrideAccessOK = member.isPublic || { // member is public, definitely same or relaxed access
(!other.isProtected || member.isProtected) && // if o is protected, so is m
((!isRootOrNone(ob) && ob.hasTransOwner(mb)) || // m relaxes o's access boundary
(other.isJavaDefined && other.isProtected)) // overriding a protected java member, see #3946 #12349
}
/* ... */ Recreated Pull-Request for the above fix. Cases that can be improved.
In the cases shown below, it seems that measures need to be taken continuously. Cases that cannot be improved.
|
I think
For
Why should that not compile? Is Scala's (Aparently I was already into this kind of stuff >10 years ago... #3946) |
I agree, it's just a by-product of allowing overrides for
At In Scala 3,
I'm sorry it's complicated, but it's correct that it partially compiles. Below is the sample code. // p/C.java
package p;
public class C { protected int f() { return 1; } } // q/D.scala
package q
import p.C
class D extends C { protected[q] override def f = 2 } // package q is unrelated for package p. // p/E.scala
package p
import q.D
object E {
def main(args: Array[String]): Unit = {
val c: C = new D()
val d: D = new D()
c.f() // OK, protected in Java allows access from the same package.
d.f() // NG, since p is a package unrelated to q, it cannot be accessed from variables of subclass type.
}
}
It seems that he closed the lid without knowing it. So, at least I think it's barren to dig into Finally, note that Scala is a bit clever when overriding |
Instead of saying, "Java protected includes package visibility," one could say that it extends default access (package access) by including subclasses in a different package. The JLS says the intention is to allow access by "code which is responsible for the implementation of that object." Because inheritance is brittle, it makes sense that only subclasses and members of the current package can access Instead of assimilating the Java model, Scala could do what is done with parens in method signatures of overrides: if an ancestor override is Java-defined, then the Java rule obtains: namely, protected has exactly Java semantics (and can't be widened). |
Yes, the type checker doesn't treat it as an override, but the backend emits the same signature, which turns it into an override. We could rename the method (as it's private). But I think it's better to disallow
Good ponit. It's under
The override should be rejected, But Am I missing something?
Ah, great observation, I didn't realize..! So maybe it makes sense to allow package a;
public class A {
protected int f() { return 1; }
void foo(b.B b) {
b.f(); // not allowed
((A)b).f(); // ok
}
}
package b;
public class B extends a.A {
@Override protected int f() { return 2; }
} |
Unfortunately, I don't know the answer either... Override Java's
|
At this point, I believe it's probalby best if the Scala compiler is a little bit too permissive, even if some overrides should be rejected. I think the fixes you did in 9525 are good. But the corner cases of I would much rather see #9334 fixed, as this compiles but causes a run-time error. |
Yes, I very much agree. With the fix of 9525, it will be treated the same as Dotty except for the The modification of |
reproduction steps
using Scala 2.13.5, on Oracle Java SE Development Kit 8u202.
I tried overriding a method in a Java class.
I changed each other's access modifiers as shown in the table below and verified.
It summarizes whether it can be compiled and whether it is the expected result.
Rules for overriding from Java.
JavaSuper
)ScalaSub
)public
public
)public
protected
public
private
public
protected[Cls]
public
private[Cls]
public
protected[pkg]
public
private[pkg]
public
protected[this]
public
private[this]
protected
public
)protected
protected
protected
private
protected
protected[Cls]
protected
private[Cls]
protected
protected[pkg]
protected
private[pkg]
protected
protected[this]
protected
private[this]
public
)protected
private
protected[Cls]
private[Cls]
protected[pkg]
private[pkg]
protected[this]
private[this]
private
public
)private
protected
private
private
private
protected[Cls]
private
private[Cls]
private
protected[pkg]
private
private[pkg]
private
protected[this]
private
private[this]
problem
Subclasses have stricter access privileges.
Cases
JavaSuper
)ScalaSub
)public
protected
public
protected[Cls]
public
private[Cls]
public
protected[pkg]
public
private[pkg]
It becomes inaccessible from directly under the package to which the class
JavaSuper
.Cases
JavaSuper
)ScalaSub
)protected
protected
protected
protected[Cls]
protected
protected[Cls]
private[Cls]
If
pkg
or its subpackages are unrelated to thejavapkg
, they will be inaccessible fromjavapkg
.Cases
JavaSuper
)ScalaSub
)protected
protected[pkg]
Access modifiers on the subclass side do not work.
Cases
JavaSuper
)ScalaSub
)public
protected[this]
protected
protected[this]
protected[this]
※Treated the same as the modifier on the
JavaSuper
side. (Very confusing!)Calling via
ScalaSub
throwjava.lang.IllegalAccessError
, calling viaJavaSuper
callsfn()
on theJavaSuper
side.Cases
As reported in private[this] subverts override accessibility check #11913.
JavaSuper
)ScalaSub
)public
private[this]
protected
private[this]
private[this]
5.
is not mentioned here because the issue already exists.2.
and3.
may be unavoidable due to Java package access specifications, so I'm not going to go into it.I think problem is
1.
and4.
.I didn't expect that
public
methods could be overridden with stricter modifiers orprotected[this]
wouldn't work.Please let me know if these are specifications.
Supplement
1.
is only occurs if you override a method defined in a Java classes in Scala 2.8.2 or later.4.
is even before Scala 2.8.1, it seems thatprotected
can be overridden withprotected[this]
, allowing access via another instance.I think the problem became more noticeable as we were able to override
public
etc, in 2.8.2.By the way, in Scala 3.0.0-RC1, an error occurred when the
JavaSuper
side waspublic
and package access, and the result was as expected.(Java's
protected
is still suspicious even in Scala 3... But that should be mentioned in Dotty.)The text was updated successfully, but these errors were encountered: