Subtyping mit Java-TX Funktionstypen #337

Closed
opened 2024-05-17 15:28:11 +00:00 by i21023 · 4 comments
Collaborator

Laut dem DHBW Insights sollten die Argumente der Funkionstypen automatisch immer Kontravariant und der Rückgabewert Kovariant sein. Der Code kompiliert auch wie ich es erwarten würde, daher gehe ich aus, dass das Feature bereits Implementiert ist, im Bytecode gibt es aber einen Fehler, wodurch zur Laufzeit eine Exception fliegt.

Beispiel

import java.lang.Object;
import java.lang.Number;
import java.lang.Integer;

public class Variance {
    public void main() {
        Fun1$$<Object, Integer> fun1 = x -> x.hashCode() + 1;
        Fun1$$<Number, Number> fun2 = fun1;
    }
}

Wenn ich diese Klasse nun über eine Main Klasse aufrufe, fliegt eine ClassCastException zur Laufzeit.

class Main{
   public static void main(String[] args) {
        new Variance().main();
   } 
}

Exception in thread "main" java.lang.ClassCastException: class Variance$$Lambda/0x000071f1dc001000 cannot be cast to class Fun1$$Ljava$lang$Number$$Ljava$lang$Number$$ (Variance$$Lambda/0x000071f1dc001000 and Fun1$$Ljava$lang$Number$$Ljava$lang$Number$$ are in unnamed module of loader 'app')
at Variance.main(Unknown Source)
at Main.main(Main.java:4)

Hier der Bytecode der main Funktion. Das Problem ist wohl der Typecast bei 14:.

  public void main();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aconst_null
         1: astore_1
         2: aload_0
         3: invokedynamic #39,  0             // InvokeDynamic #0:apply:(LVariance;)LFun1$$Ljava$lang$Object$_$Ljava$lang$Integer$_$;
         8: dup
         9: astore_1
        10: pop
        11: aconst_null
        12: astore_2
        13: aload_1
        14: checkcast     #41                 // class Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$
        17: dup
        18: astore_2
        19: pop
        20: return
        21: athrow
      StackMapTable: number_of_entries = 1
        frame_type = 255 /* full_frame */
          offset_delta = 21
          locals = []
          stack = [ class java/lang/Throwable ]
    Signature: #7                           // ()V
      JavaTXSignature: length = 0x2 (unknown attribute)
       00 30
Laut dem DHBW Insights sollten die Argumente der Funkionstypen automatisch immer Kontravariant und der Rückgabewert Kovariant sein. Der Code kompiliert auch wie ich es erwarten würde, daher gehe ich aus, dass das Feature bereits Implementiert ist, im Bytecode gibt es aber einen Fehler, wodurch zur Laufzeit eine Exception fliegt. ### Beispiel ```java import java.lang.Object; import java.lang.Number; import java.lang.Integer; public class Variance { public void main() { Fun1$$<Object, Integer> fun1 = x -> x.hashCode() + 1; Fun1$$<Number, Number> fun2 = fun1; } } ``` Wenn ich diese Klasse nun über eine Main Klasse aufrufe, fliegt eine ClassCastException zur Laufzeit. ```java class Main{ public static void main(String[] args) { new Variance().main(); } } ``` Exception in thread "main" java.lang.ClassCastException: class Variance$$Lambda/0x000071f1dc001000 cannot be cast to class Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$ (Variance$$Lambda/0x000071f1dc001000 and Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$ are in unnamed module of loader 'app') at Variance.main(Unknown Source) at Main.main(Main.java:4) Hier der Bytecode der main Funktion. Das Problem ist wohl der Typecast bei `14:`. ``` public void main(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=2, locals=3, args_size=1 0: aconst_null 1: astore_1 2: aload_0 3: invokedynamic #39, 0 // InvokeDynamic #0:apply:(LVariance;)LFun1$$Ljava$lang$Object$_$Ljava$lang$Integer$_$; 8: dup 9: astore_1 10: pop 11: aconst_null 12: astore_2 13: aload_1 14: checkcast #41 // class Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$ 17: dup 18: astore_2 19: pop 20: return 21: athrow StackMapTable: number_of_entries = 1 frame_type = 255 /* full_frame */ offset_delta = 21 locals = [] stack = [ class java/lang/Throwable ] Signature: #7 // ()V JavaTXSignature: length = 0x2 (unknown attribute) 00 30 ```
Owner

Ich glaube das Problem ist, dass beide Variablen jeweils den kompletten Funktionstyp als Typ bekommen.
Da müssen wir nochmal drüber sprechen, bin mir nicht ganz sicher was korrekt wäre.

Ich glaube das Problem ist, dass beide Variablen jeweils den kompletten Funktionstyp als Typ bekommen. Da müssen wir nochmal drüber sprechen, bin mir nicht ganz sicher was korrekt wäre.
Owner

Da in JavaTX-Bytecode dann tasächlich implizit

LFun1$$Ljava$lang$Object$_$Ljava$lang$Integer$_$ 

ein Subtyp von

Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$

ist

müsste man wahrscheinlich einen Cast einfügen (s.u.)

import java.lang.Object;
import java.lang.Number;
import java.lang.Integer;

public class Variance {
    public void main() {
        Fun1$$<Object, Integer> fun1 = x -> x.hashCode() + 1;
        Fun1$$<Number, Number> fun2 = 
                     (Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$)fun1;
    }
}
Da in JavaTX-Bytecode dann tasächlich implizit ``` LFun1$$Ljava$lang$Object$_$Ljava$lang$Integer$_$ ``` ein Subtyp von ``` Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$ ``` ist müsste man wahrscheinlich einen Cast einfügen (s.u.) ```java import java.lang.Object; import java.lang.Number; import java.lang.Integer; public class Variance { public void main() { Fun1$$<Object, Integer> fun1 = x -> x.hashCode() + 1; Fun1$$<Number, Number> fun2 = (Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$)fun1; } } ```
Owner

Das Problem ist, dass ich momentan wann immer Fun1$$<Number, Number> kommt das ganze direkt in Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$ übersetze. Ich glaube es gibt momentan gar keine Entsprechung für die erste Variante.

Das Problem ist, dass ich momentan wann immer `Fun1$$<Number, Number>` kommt das ganze direkt in `Fun1$$Ljava$lang$Number$_$Ljava$lang$Number$_$` übersetze. Ich glaube es gibt momentan gar keine Entsprechung für die erste Variante.
Owner

Man muss in jedes Interface FunN$$Typ$_$...$_$ alle Superinferfaces eintragen

Man muss in jedes Interface `FunN$$Typ$_$...$_$` alle Superinferfaces eintragen
Sign in to join this conversation.
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: JavaTX/JavaCompilerCore#337
No description provided.