Skip to content
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

Cannot Compile Call to clone() on Java Interface That Defines It. #10501

Closed
dccorona opened this issue Sep 7, 2017 · 3 comments
Closed

Cannot Compile Call to clone() on Java Interface That Defines It. #10501

dccorona opened this issue Sep 7, 2017 · 3 comments

Comments

@dccorona
Copy link

dccorona commented Sep 7, 2017

In Java, interfaces are allowed to define that their implementations must expose public clone() methods (the example reference here is IonValue from the package ion-java).

For some reason, the scala compiler (tested with 2.11.8 and 2.12.3) doesn't "see" these overridden methods, instead trying and failing to compile against Object.clone, which is protected.

Scala's behavior when trying to implement something similar via a trait seems to allude to what the problem is:

scala> trait MyCloneable extends Cloneable {
  override def clone(): MyCloneable
}
     |      | <console>:17: error: overriding method clone in trait MyCloneable of type ()MyCloneable;
 method clone in class Object of type ()Object has weaker access privileges; it should be public;
 (Note that method clone in trait MyCloneable of type ()MyCloneable is abstract,
  and is therefore overridden by concrete method clone in class Object of type ()Object)
       trait MyCloneable extends Cloneable {
             ^

That, in and of itself, is fine. Scala doesn't allow you to do this, and that's ok. The problem is that Java does allow this, as seen in ion-java. This ultimately creates Java code that is impossible to call from Scala (presumably because Scala's rules for precedence in the face of inheritance differs slightly from Java, but that's just a hunch). Here is what happens when you try to call clone() as defined on a Java interface:

scala> 
import com.amazon.ion.IonValue
import com.amazon.ion.system.IonSystemBuilder

val isys = IonSystemBuilder.standard().build()
val iv: IonValue = isys.newEmptyStruct()
val ivc = iv.clone()

scala> import com.amazon.ion.IonValue
scala> import com.amazon.ion.system.IonSystemBuilder
scala> isys: com.amazon.ion.IonSystem = com.amazon.ion.impl.lite.IonSystemLite@1e226bcd
scala> iv: com.amazon.ion.IonValue = {}
scala> <console>:14: error: method clone in class Object cannot be accessed in com.amazon.ion.IonValue
 Access to protected method clone not permitted because
 prefix type com.amazon.ion.IonValue does not conform to
 object $iw where the access take place
       val ivc = iv.clone()
                    ^

The problem here is that Java has allowed code that defines clone() in an interface to be compiled, and when that code is called from Java, it is then allowed to be accessed. However (seemingly because of Scala's slightly different rules for abstract methods), it is impossible to call these methods without reflection.

The expected behavior, of course, is that you can call clone() as defined on interfaces from Scala in more or less exactly the same way as you can from Java.

@som-snytt
Copy link

Also comments to #151

@hrhino
Copy link
Member

hrhino commented Sep 10, 2017

Driving by and noting that the issue numbers (#151 and #10501) have a nice similarity.

@SethTisue SethTisue added this to the Backlog milestone Feb 14, 2023
@som-snytt
Copy link

Despite the beautiful symmetry of ticket numbers, duplicates #6760

Also see #12892 and its proposed fix.

@som-snytt som-snytt closed this as not planned Won't fix, can't repro, duplicate, stale Jan 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants