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

java signature requirements lead to unsoundness in non-covariant positions #4388

Closed
scabug opened this issue Mar 25, 2011 · 6 comments
Closed

Comments

@scabug
Copy link

scabug commented Mar 25, 2011

The following program compiles with no warnings, then throws a CCE when run.

import scala.math.Ordering;
import scala.math.Ordering$;

public class J {
  public static void main(String[] args) {
    // Here's where we are really punished...
    // Again I see the generation of a Character method
    // as the only way out.
    Ordering<Object> charOrd = Ordering.Char$.MODULE$;
    
    charOrd.compare(new Object(), new Object());
  }
}
% scala29 J
java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.Character
	at scala.runtime.BoxesRunTime.unboxToChar(Unknown Source)
	at scala.math.Ordering$$Char$$.compare(Ordering.scala:181)
	at J.main(J.java:10)

In 2.8.1 it fails to compile in the desirable way, because Ordering.Char is an Ordering.
(Note that 2.8.1 requires a slightly different code because of changes to the InnerClasses attribute)

// 2.8 only
import scala.math.Ordering;
import scala.math.Ordering$;
import scala.math.Ordering$Char$;

public class J {  
  public static void main(String[] args) {
    // Here's where we are really punished...
    // Again I see the generation of a Character method
    // as the only way out.
    Ordering<Object> charOrd = Ordering$Char$.MODULE$;
    
    charOrd.compare(new Object(), new Object());
  }
}
J.java:8: incompatible types
found   : scala.math.Ordering$$Char$$
required: scala.math.Ordering<java.lang.Object>
    Ordering<Object> charOrd = Ordering$$Char$$.MODULE$$;
                                             ^
1 error

But that was changed in an attempt to fix #4214, as explained in the commit message for r24363:

Another lap around the track with generic signatures.
At the root of the issue reported in SI-4214 is our old friend
(fondly remembered from the days of primitive equality)
boxed/primitive unification.

  // scala
  trait T[A] {
    def f(): A
  }
  // the generic signature spec doesn't allow for parameterizing
  // on primitive types, so this cannot remain Char.  However
  // translating it to Character, as was done, also has issues.
  class C extends T[Char] {
    def f(): Char = 'a'
  }

  // Note that neither of the signatures for f, the implementation
  // or the bridge method, matches the type parameter.
  Generic interfaces in class:
    T<java.lang.Character>
  Generic signatures:
    public char C.f()
    public java.lang.Object C.f()

After this commit, primitive type parameters are translated into
Object instead of the boxed type.  It was martin's idea, so no review.
Closes SI-4214.

Again I see no way out which does not involve generating more bridge methods which put things in boxes and take things out of other boxes.

@scabug
Copy link
Author

scabug commented Mar 25, 2011

Imported From: https://issues.scala-lang.org/browse/SI-4388?orig=1
Reporter: @paulp
See #4214, #5517

@scabug
Copy link
Author

scabug commented Mar 25, 2011

@odersky said:
I see. But I think we are almost there. I believe that instead of representing

T[Char] as T<java.lang.Character> or T, which are both unsound, we should simply represent it as the raw type T.

@scabug
Copy link
Author

scabug commented Mar 25, 2011

@paulp said:
Replying to [comment:2 odersky]:

I see. But I think we are almost there. I believe that instead of representing

T[Char] as T<java.lang.Character> or T, which are both unsound, we should simply represent it as the raw type T.

I'm so accustomed to shunning raw types, I hadn't considered it. You may be right.

@scabug
Copy link
Author

scabug commented Mar 25, 2011

@paulp said:
I don't want to duplicate effort; if you're going to try that out I'll work on something else, but if you want I can attempt it.

@scabug
Copy link
Author

scabug commented Mar 26, 2011

@odersky said:
No, please have a go, if you wish. It won't ``solve_ the problem completely, nothing can. The problem is there are certain types such as Ordered[Char] that we can express in Scala but not in Java. So, calling Java -> Scala for members involving these types, we have to accept that certain type tests will be done dynamically. The only shortcoming of the present situation is that a type failure manifests itself in a ClassCastException, not in an UnsupportedOperation exception. But I think that's rather cosmetic, and the alternative of putting in all these bridge methods for the sake of Java would be too costly.

Using raw T instead of T helps only for method results. For method arguments its an improvement only in sofar as it makes it clearer there's probably a dynamic type test going on under the covers. But it does so only if a human inspects the Java signature, and who ever does? So, I think it's really mostly a cosmetic change. I would leave it alone until 2.9 ships in any case. The current situation is OK, and the risk of changing things around now is too high.

@scabug
Copy link
Author

scabug commented Aug 11, 2016

@SethTisue said:
Tempted to just close as wontfix.

@scabug scabug added this to the Backlog milestone Apr 7, 2017
@SethTisue SethTisue closed this as not planned Won't fix, can't repro, duplicate, stale Oct 23, 2023
@SethTisue SethTisue removed this from the Backlog milestone Oct 23, 2023
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

2 participants