-
Notifications
You must be signed in to change notification settings - Fork 21
scalac allows overriding protected member with weaker privileges #3946
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
Comments
Imported From: https://issues.scala-lang.org/browse/SI-3946?orig=1 |
@lrytz said: |
@lrytz said: |
@lrytz said: // J1.java
package bip;
public class J {
// package[bip] + protected f()
protected void f() { }
} // J2.java
package notbip;
public class J2 extends bip.J {
// this override "should" not be allowed, it excludes package bip
// now package[notbip] + protected f()
@Override
protected void f() { }
} // J3.java
package bip;
public class J3 {
public void g(bip.J x) {
x.f(); // ok
notbip.J2 y = (notbip.J2)x;
y.f(); // fails
// J3.java:7: f() has protected access in notbip.J2
// y.f();
// ^
// 1 error
}
} |
@lrytz said: Summing up. Given the Java class: package p;
public class A {
protected void f() {}
} This indeed means, in Scala terms, "f" is "protected[p]", i.e. we should set package p {
object T {
val a = new A()
a.f()
}
} This has been fixed in #3946, but with the unfortunate consequence on package q {
class B extends p.A {
override protected def f() { }
}
} Note that the same situation is much more unlikely to happen in We concluded in our discussion that
The easiest solution seems to be a special case when checking the |
@SethTisue said: |
Compiling under Scala 2.13, we see two identical compilation errors for traits `RssAtomModule` & `GModule`, which both extend the `com.sun.syndication.feed.module.Module` interface from ROME (used for processing RSS). The message is of the form: > weaker access privileges in overriding def clone(): Object (defined in trait Module) > override should be public; > (note that def clone(): Object (defined in trait Module) is abstract, and is therefore > overridden by concrete protected[package lang] def clone(): Object (defined in class Object)) `com.sun.syndication.feed.module.Module` is a Java interface that specifies `clone()` should be *public*: ``` public Object clone() throws CloneNotSupportedException; ``` ...but it's just an interface, not a class - and so the `java.lang.Object.clone()` method, which is assigned `protected` as an access modifier, is more protected than the interface dictates - but it's the only `clone()` method available on our _trait_, whether that's `RssAtomModule` or `GModule`. This is a horrible little problem and various people have encountered it over the years: * scala/bug#3946 * https://bugs.openjdk.org/browse/JDK-6946211 How to fix? ----------- There is a fairly good suggestion at https://stackoverflow.com/a/8619704/438886 - just define a concrete `clone()` method in the trait, with a guard implmentation that just throws `CloneNotSupportedException` - your concrete subclasses can override the method with whatever implementation they like. It's a bit of a hack, but it works. However, looking at the code of these two traits and their solitary implementations: * `RssAtomModule` with its implementation `RssAtomModuleImpl` * `GModule` with `GModuleImpl` ...there's no reason to separate the functionality here into a separate trait and class. It's not being used to facilitate testing, and each trait has only a single implementation. Sometimes a trait can be a nice way to decide exactly what limited public API you want people to think about when they use your code, but I don't think that's the case here. Totally fine to just unite each trait & class into a simple class, reducing unnecessary boilerplate, and removing the need to have a dummy `public` clone method! The compilation errors in full: ``` [error] /Users/roberto/guardian/frontend/common/app/common/ShowcaseRSSModules.scala:16:7: weaker access privileges in overriding [error] def clone(): Object (defined in trait Module) [error] override should be public; [error] (note that def clone(): Object (defined in trait Module) is abstract, [error] and is therefore overridden by concrete protected[package lang] def clone(): Object (defined in class Object)) [error] trait RssAtomModule extends com.sun.syndication.feed.module.Module with Serializable with Cloneable { [error] ^ [error] /Users/roberto/guardian/frontend/common/app/common/ShowcaseRSSModules.scala:52:7: weaker access privileges in overriding [error] def clone(): Object (defined in trait Module) [error] override should be public; [error] (note that def clone(): Object (defined in trait Module) is abstract, [error] and is therefore overridden by concrete protected[package lang] def clone(): Object (defined in class Object)) [error] trait GModule extends com.sun.syndication.feed.module.Module with Serializable with Cloneable { [error] ^ ```
Compiling under Scala 2.13, we see two identical compilation errors for traits `RssAtomModule` & `GModule`, which both extend the `com.sun.syndication.feed.module.Module` interface from ROME (used for processing RSS). The message is of the form: > weaker access privileges in overriding def clone(): Object (defined in trait Module) > override should be public; > (note that def clone(): Object (defined in trait Module) is abstract, and is therefore > overridden by concrete protected[package lang] def clone(): Object (defined in class Object)) `com.sun.syndication.feed.module.Module` is a Java interface that specifies `clone()` should be *public*: ``` public Object clone() throws CloneNotSupportedException; ``` ...but it's just an interface, not a class - and so the `java.lang.Object.clone()` method, which is assigned `protected` as an access modifier, is more protected than the interface dictates - but it's the only `clone()` method available on our _trait_, whether that's `RssAtomModule` or `GModule`. This is a horrible little problem and various people have encountered it over the years: * scala/bug#3946 * https://bugs.openjdk.org/browse/JDK-6946211 How to fix? ----------- There is a fairly good suggestion at https://stackoverflow.com/a/8619704/438886 - just define a concrete `clone()` method in the trait, with a guard implmentation that just throws `CloneNotSupportedException` - your concrete subclasses can override the method with whatever implementation they like. It's a bit of a hack, but it works. However, looking at the code of these two traits and their solitary implementations: * `RssAtomModule` with its implementation `RssAtomModuleImpl` * `GModule` with `GModuleImpl` ...there's no reason to separate the functionality here into a separate trait and class. It's not being used to facilitate testing, and each trait has only a single implementation. Sometimes a trait can be a nice way to decide exactly what limited public API you want people to think about when they use your code, but I don't think that's the case here. Totally fine to just unite each trait & class into a simple class, reducing unnecessary boilerplate, and removing the need to have a dummy `public` clone method! The compilation errors in full: ``` [error] /Users/roberto/guardian/frontend/common/app/common/ShowcaseRSSModules.scala:16:7: weaker access privileges in overriding [error] def clone(): Object (defined in trait Module) [error] override should be public; [error] (note that def clone(): Object (defined in trait Module) is abstract, [error] and is therefore overridden by concrete protected[package lang] def clone(): Object (defined in class Object)) [error] trait RssAtomModule extends com.sun.syndication.feed.module.Module with Serializable with Cloneable { [error] ^ [error] /Users/roberto/guardian/frontend/common/app/common/ShowcaseRSSModules.scala:52:7: weaker access privileges in overriding [error] def clone(): Object (defined in trait Module) [error] override should be public; [error] (note that def clone(): Object (defined in trait Module) is abstract, [error] and is therefore overridden by concrete protected[package lang] def clone(): Object (defined in class Object)) [error] trait GModule extends com.sun.syndication.feed.module.Module with Serializable with Cloneable { [error] ^ ```
Given the the following files:
p/J.java
p/S.scala
Compiling them together with
scalac
gives the correct error message:However, when compiling first the Java file, then the Scala file there's no error message:
The text was updated successfully, but these errors were encountered: