ceylon / ceylon-compiler

DEPRECATED
GNU General Public License v2.0
138 stars 36 forks source link

detect Java types which are actually covariant #1474

Open gavinking opened 10 years ago

gavinking commented 10 years ago

So I just noticed that java.lang.Class is actually a covariant type, though of course that is totally implicit. I suppose there's quite likely a bunch of other Java types like that. We should make the model loader detect Java types which are actually co-(or contra-)variant and add that information to the model.

See this stack overflow question:

http://stackoverflow.com/questions/20241368/how-to-turn-a-ceylon-class-which-extends-a-java-class-into-the-java-class

renatoathaydes commented 10 years ago

I am having trouble because of this issue... I need to subclass some JavaFX classes and I can't do it in Ceylon! My latest example:

class CeylonListener<Prop>() satisfies ChangeListener<Prop> {

    shared actual void changed(ObservableValue<Prop>? obs, Prop? old, Prop? newValue) {

    }
}
name clash: changed(javafx.beans.value.ObservableValue<Prop>,Prop,Prop) in ceylonfx.binding.CeylonListener and changed(javafx.beans.value.ObservableValue<? extends T>,T,T) in javafx.beans.value.ChangeListener have the same erasure, yet neither overrides the other 
Backend Error
gavinking commented 10 years ago

@renatoathaydes try this:

Ceylon:

import javafx.beans.\ivalue {
    ObservableValue
}
shared class Event<out T>(ObservableValue<T> observableValue) {
    shared T observable => observableValue.\ivalue; 
}

Java:

package ceylonfx.application.java;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;

public abstract class Listener<T> implements ChangeListener<T> {
    private static <X> Event<X> toEvent(ObservableValue<X> observableValue) {
        return new Event<X>(null, observableValue);
    }
    public void changed(ObservableValue<? extends T> observable,
            T oldValue,
            T newValue) {
        onChange(toEvent(observable), oldValue, newValue);
    }
    public abstract void onChange(Event<? extends T> observable,
            T oldValue,
            T newValue);
}

P.S. I had to enable "Java classes calling Ceylon" in the IDE project properties.

renatoathaydes commented 10 years ago

Almost the same as what I did! https://github.com/renatoathaydes/CeylonFX/commit/03dd308f7081d6156160261d7a6c9ee1d76eae4e#diff-038d650dc1b4e34656db129b784cde31R8

FroMage commented 10 years ago

That sounds impossible in the general case, no? I mean, if in order to determine if a type parameter appears only in covariant location, we need to know if some places are covariant locations, which is infinite.

FroMage commented 10 years ago

Moving to 1.2

gavinking commented 10 years ago

Aw man, well at least do it for j.l.Class and any other especially important cases in java.base.

Detecting that a class is covariant is not hard, BTW, we already have code in the typechecker that could very easily be repurposed.

gavinking commented 10 years ago

I think we should do this for 1.1.

tombentley commented 10 years ago

Detecting that a class is covariant is not hard, BTW, we already have code in the typechecker that could very easily be repurposed.

Great; where?

gavinking commented 10 years ago

Well, look at TypeArgumentVisitor.

FroMage commented 10 years ago

In this case: A and B are only covariant in T if both are covariant. This accepts two solutions: that both are covariant, or none are. This doesn't sound at all like a tractable problem, or one for which you have code, since the typechecker doesn't do variance inference.

class A<T> {
 public B<T> f(){ return null; }
}
class B<T> {
 public A<T> f(){ return null; }
}

Otherwise, sure I can special-case java.lang.Class for now if you want.

gavinking commented 10 years ago

@FroMage Well, OK, that's a pretty good point. So sure, we would miss some cases, since we would have to assume that most container types are invariant (except for arrays). But surely we would still be able to detect quite a few Java types as covariant.

FroMage commented 10 years ago

We explicitly made Java arrays invariant ;)