Forum Stats

  • 3,852,844 Users
  • 2,264,142 Discussions
  • 7,905,157 Comments

Discussions

Generic Covariant Java Syntax Only Discussion

843793
843793 Member Posts: 41,732 Green Ribbon
edited Sep 4, 2002 11:29AM in Generics
I have been looking at the 1.2 prototype and comments about it.
Much of the syntax seems unclear and ends up in discussions such as it works for me, generally followed by not if you pass in such and such.
Some of the syntax I saw in some old specs doesn?t seem to be getting any attention at all and so I am unsure if it is still included or not.
The biggest problem is some people (understandably) find much of the proposed syntax hard to understand and just glaze over it, without a complete understanding of what it is trying to do.
I want to discuss the syntax without getting into any details about how java achieves this (code bloat, extra runtime checks etc), in order to understand what should be legal syntax and what the results should be (without having to test it and find out).
Note I am all for both Generic and Covariant Java, so the following assumes we want to do both. Covariant Java means that Object foo() could be overwritten by String foo(), currently Java doesn't allow this (except for with arrays), and so other syntax rules of Java would also need to be changed accordingly.
So in order for Java not to make the same mistakes as many other languages here is my 2 cents worth.

Syntax Examples:

1)
class SampleClass1<TypeA extends Number>
TypeA can be any numerical primitive type (not boolean or char), or any class that extends Number. (Current proposal allows primitive use to be defined in the same way as Object use?)

2)
class SampleClass2<TypeB extends Button implements Comparable, Serializable>
TypeB can be any class that extends Button and implements both Comparable and Serializable. Hence methods from any of these 3 things can be used on TypeB. (Current proposal allows both extends and implements?)

3)
class SampleChildClass3<TypeC, TypeD> extends SampleParentClass3<TypeD>
TypeC can be any class, however TypeD may be bounded by the SampleParentClass3. SampleParentClass3 may have restricted TypeD to extend something. (Current proposal stops us from bounding TypeD any further when it is used by the parent class?)

4)
new SampleClass1();
All the methods using TypeA will take and return Number instead. (Current proposal allows us to create a new instance of Syntax Example 1 without having to explicitly state the extending Type?)

5)
new SampleClass1<double>();
All the methods using TypeA will take and return double instead. (Current proposal allows primitives?)

6)
static TypeC sampleMethod6(TypeD aValue) {?}
TypeC and TypeD are determined when the class is loaded. This method may be found in the class from Syntax Example 3. (Current proposal allows us to define static methods without any generic typing before the static keyword?)

7)
int i = SampleChildClass3<int, String>.sampleMethod6("hello");
The class explicitly determines the parameter types, not implicitly by using the parameters. (Current proposal no longer allows implicit typing as in perl and other such languages?)

More advanced (Covariant) Syntax Examples:

8)
SampleParentClass3<String> a = new SampleChildClass3<int, String>;
SampleChildClass3<int, String> b = (SampleChildClass3<int, String>)a; //legal
SampleChildClass3<long, String> c = (SampleChildClass3<long, String>)a; //legal (due to covariance)
SampleChildClass3<byte, String> d = (SampleChildClass3<byte, String>)a; //runtime error
SampleChildClass3<int, Object> e = (SampleChildClass3<int, Object>)a; // legal (due to covariance)
SampleChildClass3<int, Button> f = (SampleChildClass3<int, Button>)a; //compile error
(Current proposal is consistent with this?)

9)
SampleChildClass3<int, String>.class.getMethod("sampleMethod6", new Class[] {String.class});
Class.forName("SampleParentClass3", new Class[] {String.class});
(Current proposal supports reflection, inner classes etc.?)

10)
(new Collection<Object>).getClass().equals(new Collection().getClass()) // true
(new Collection<String>).getClass().equals(new Collection().getClass()) // false
(Current proposal follows normal Java rules for instanceof and getClass etc.?)

Answers / Comments please?

Comments

  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    class SampleClass1<TypeA extends Number>

    TypeA can be any numerical primitive type (not boolean or char), or any > class that extends Number. (Current proposal allows primitive use to be > defined in the same way as Object use?)
    No, the current implementation of generics works only with reference types, not primitive types.

    I have to stop you here and ask you what you read that made you confused about this point. It seems like you're reading the wrong documentation, and this may be the source of the majority of your questions.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    I have read many documents about this over the last few years, including PolyJ and GJ etc. Taken from JSR-14: The original JSR indicated that supporting primitive type parameters to generics was not a goal of the project. This was based both on philosophical considerations and on technical problems. and also A variation that circumvents some of the conceptual difficulties is to uniformly declare that primitive types are in fact subtypes of their corresponding reference types. For example, int would be a subtype of Integer and so on.
    .

    In some other Generic Implementations primitives are supported, and the expert group hasn't ruled out using primitive types. If (I hope when) they do propose to use primitive types, I would like to know what the syntax would be? (Schapel has said it doesn't currently support primitives, so this may still be up for much discussion)
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    If you're trying to understand the 1.2 prototype, then JSR-14 is probably the wrong thing to read.

    The documents you want to read are here:
    http://www.research.avayalabs.com/user/wadler/pizza/gj/

    Other documents, such as those on JSR-14, PolyJ, or NextGen, will likely confuse you if you're trying to use the prototype version 1.2 implementation.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    Note:
    the original message number 8 should say:
    SampleParentClass3<String> a = new SampleChildClass3<int, String>;
    SampleChildClass3<int, String> b = (SampleChildClass3<int, String>)a; //legal
    SampleChildClass3<long, String> c = (SampleChildClass3<long, String>)a; //runtime error
    SampleChildClass3<byte, String> d = (SampleChildClass3<byte, String>)a; //runtime error
    SampleChildClass3<int, Object> e = (SampleChildClass3<int, Object>)a; // compile error
    SampleChildClass3<int, Button> f = (SampleChildClass3<int, Button>)a; //compile error
    The covariance shouldn't make any difference, this same syntax could be implemented with or without covariance
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    The http://www.research.avayalabs.com/user/wadler/pizza/gj/ link is not currently working. I have an old document called gj-specification dated May 1998 (that I think came from there).
    I hope the proposal has changed from that.

    Some of my comments about the gj-specification (May 1998):

    Section 2.2)
    Vector<String> x = new Vector<String>();
    Vector<Integer> y = new Vector<Integer>();
    return x.getClass() == y.getClass(); // returns true
    This changes all sorts of java rules: reflection, casting, instanceof would no longer work as expected. For example this would seem to imply that casting would allow (Vector<String>)y in which case one could assign an Integer to a String without the compiler complaining.

    Section 2.5)
    Cell x = new Cell<String>("abc");
    x.value; // OK, has type Object
    x.get(); // OK, has type Object
    x.put("def"); // deprecated
    The 1st line shouldn't be allowed even by casting.
    The logic seems to be that this had to be allowed during the transition to Generic Code. A side affect of this is any calls to methods that have generic parameters are deprecated. These methods should not be deprecated as then whenever someone wants to use Generic Code, they would have to explicitly state the types Cell<Object> instead of Cell, hence implying lots of code changes.

    Section 3.1)
    class Test {
      private static Object x;
    
      public static <TypeA> void setX(TypeA aValue) {
        x = aValue;
      }
    
      public static <TypeA> TypeA getX() {
        return (TypeA)x;
      }
    
      public static void main(String[] args) {
        <String>setX("Hello");
        System.out.println(<String>getX());
        <Integer>setX(new Integer(1));
        System.out.println(<String>getX());
      }
    }
    Looking at the above code I don't even know what would happen.
    I don't know what the power of allowing such code is.
    I find the following much simpler to understand:
    class Test<TypeA> {
      private static TypeA x;
    
      public static void setX(TypeA aValue) {
        x = aValue;
      }
    
      public static TypeA getX() {
        return x;
      }
    
      public static void main(String[] args) {
        Test<String>.setX("Hello");
        System.out.println(Test<String>.getX());
        Test<Integer>.setX(new Integer(1));
        System.out.println(Test<Integer>.getX());
      }
    }
    Section 5.3)
    Object o;
    (Hashtable<String,Integer>)o // illegal, not unique subtype
    In java anything could be casted to or from an Object.
    I have no idea why this should be illegal.

    Section 5.6)
    static <A> Seq<A> nil() { return new Seq<A>(); }
    static <A> Seq<A> cons(A x, Seq<A> xs) { return new Seq<A>(x, xs); }
    Then the following are legal expressions:
    cons("abc", nil()) // of type: Seq<String>
    cons(new IOException(), cons(new Error(), nil())) // of type: Seq<Throwable>
    nil(); // of type: Seq<Null>
    cons(null, nil());
    As the rest of section 5.6 seems to imply, implicit bounding is a bad thing, and I have no idea what extra power it gives us. To be consistent with class Types (e.g. new LinkedList() <--> new LinkedList<Object>()) I think the following would be easier to understand:
    class Test<TypeA> {
      static Seq<TypeA> nil() { 
        return new Seq<TypeA>(); 
      }
      
      static Seq<TypeA> cons(TypeA x, Seq<TypeA> xs) { 
        return new Seq<TypeA>(x, xs); 
      }
    }
    Then the following are legal expressions:
    cons("abc", nil()) // of type: Seq<TypeA>
    cons(new IOException(), cons(new Error(), nil())) // of type: Seq<TypeA>
    nil(); // of type: Seq<TypeA>
    cons(null, nil());
    Called outside of Test we could have:
    Test.cons("abc", Test.nil()) // of type: Seq<Object>
    Test.cons(new IOException(), Test.cons(new Error(), Test.nil())) // of type: Seq<Object>
    Test.nil(); // of type: Seq<Object>
    Test.cons(null, Test.nil());
    This avoids all the complications of section 5.6.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    The
    http://www.research.avayalabs.com/user/wadler/pizza/gj/
    link is not currently working.
    Try http://www.cis.unisa.edu.au/~pizza/gj/ instead.

    Some of my comments about the gj-specification (May
    1998):

    Section 2.2)
    Vector<String> x = new
    Vector<String>();
    Vector<Integer> y = new Vector<Integer>();
    return x.getClass() == y.getClass(); // returns
    true
    This changes all sorts of java rules:
    reflection, casting, instanceof would no longer work
    as expected. For example this would seem to imply
    that casting would allow (Vector<String>)y in which
    case one could assign an Integer to a String without
    the compiler complaining.
    No, it does none of the sort. Everything still works as expected, and Vector<Integer> cannot be cast to Vector<String>.

    First, read the documentation about how Generic Java actually works. Only after you've done that can you have a meaningful discussion about them.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    Schapel

    I have read the 'documentation about how Generic Java actually works.'
    It turns out the current specification is still the gj-specification (May 1998) and so all my comments still apply.

    The Class.isInstance specification states the following:
    Determines if the specified Object is assignment-compatible with the object represented by this Class. This method is the dynamic equivalent of the Java language instanceof operator. The method returns true if the specified Object argument is non-null and can be cast to the reference type represented by this Class object without raising a ClassCastException. It returns false otherwise.

    The following code prints out true both times:
    public class IsInstance<TypeA> {
      public static void main(String args[]) {
        IsInstance<String> x = new IsInstance<String>();
        IsInstance<Integer> y = new IsInstance<Integer>();
        System.out.println(x.getClass().isInstance(x));
        System.out.println(x.getClass().isInstance(y));
      }
    }
    The instanceof equivalent doesn't even compile:
    public class Instanceof<TypeA> {
      public static void main(String args[]) {
        Instanceof<String> x = new Instanceof<String>();
        Instanceof<Integer> y = new Instanceof<Integer>();
        System.out.println(x instanceof Instanceof<String>);
        System.out.println(y instanceof Instanceof<String>);
      }
    }
    Sections 15.20 and 15.21 of the Java Language Specification (http://java.sun.com/docs/books/jls/second_edition/html/j.title.doc.html) make it very clear that there is a contradiction in the current GJ Proposal between the == and instanceof, casting etc.

    Casting and instanceof shouldn't be allowed here and aren't allowed here (testing proves this, the spec implies otherwise when read in conjunction with the above)
    The problem is that
    return x.getClass() == y.getClass();
    returns true when it should return false. It is documented to return true and does return true, but this contradicts the normal java rules as shown above.
This discussion has been closed.