Slashdot Mirror


Sun to Add Variance to Java in 1.5?

Ahe writes "I have been working on a joint project between Sun Microsystems, The University of Aarhus, and The Alexandra Institute. As you might know, Sun has for long been commited to adding generics to Java. Our project was to extend this with variance annotations for more flexible typing of parameterized classes and arrays. Recently Sun has released the project result as a new prototype with variance. If you like variance, please vote for this bug."

6 of 55 comments (clear)

  1. What is variance? by DeadSea · · Score: 4, Informative
    I've done some googling and I've come up with some quick answers. It seems it makes Java generics act more like C++ Collections in some cases.

    From http://forum.java.sun.com/thread.jsp?forum=316&thr ead=389987&start=15&range=15&tstart=0&trange=1 5:

    > I can't quite get my head round what combination of
    > VM, compiler and/or language changes would iron out
    > the following incompability between arrays and
    > generics:
    >
    > Cat[] cats = new Cat[10];
    > Animal[] animals = cats; // legal
    >
    > List cats = new List(10);
    > List animals = cats; // illegal
    > according to JSR-14

    This problem is addressed in the "variance" extension to
    the generic type system, which will be included in the
    imminent JSR14 prototype 2.0. Details are enclosed in
    the prototype.

    Also a link to a MIT research paper on variance from that thread.

  2. Re:Definitely a bug! by DeadSea · · Score: 4, Interesting
    I can see myself using generics when designing APIs. Lets say that I currently have a method that returns a list of Strings. Internally I store those Strings in a Vector so that I can add to it easily. I want users to be able to access these Strings so I create a getStrings() method. Since want the user to know that they are Strings and not have to do any casting I currently do something like this:

    public String[] getStrings(){
    String[] s = new String[vector.size()];
    return vector.toArray(s);
    }

    Maybe in the future I could just store them in a list and return that list because it is a string list specifically:

    public List<String> getStrings(){
    return list;
    }
  3. Re:Somebody understood something ? by be-fan · · Score: 4, Informative

    En anglias:

    Convariance means that, you can add a Derived to a list of Base without casting.
    Contravariance means that you can unpack a Derived from a list of Base without casting.
    Invariance is what you have in C++, where a list of Derived and a list of Base are two different things.

    --
    A deep unwavering belief is a sure sign you're missing something...
  4. Short description of variance by Ahe · · Score: 5, Informative

    The term variance covers co-variance, contra-variance, and bi-variance. In the 1.5 prototype you can use variance annotations on parameterized types.

    + means co-variant (think read-only).
    - means contra-variant (think write-only).
    * mean bi-variant (niether read nor write).

    You are familiar with co-variance from arrays in Java.

    When an array of Integer is a subtype of array of Number, arrays are said to be covariant in their element type. Consider:

    Number[] ns = new Integer[10];

    With generics, you can have a list of Numbers:

    List<Number> nl = new List<Number>();

    However, since generics are added without changing the JVM, nl can only refer to lists of exactly Number, e.g., this is wrong:

    List<Number> nl = new List<Integer>();

    So why is this wrong, consider arrays:

    Number[] ns = new Integer[10];
    ns[0] = new Double(0.0); // run-time error

    Since ns refers to an array of Integer, we cannot put Double in to it. The mechanism that catches this is called store-check.

    Since the JVM is not modified, we cannot implement a store-check for generic classes. Variance annotations allows us more flexibility, however.

    Consider this method:

    void copy(Collection<+Number> src, Collection<-Number> dst) {
    for (Number n : src) { dst.add(n); }
    }

    Here we use variance annotations to state that we will only read from src and only write to dst. In this way we are allow to make a call like this:

    List<Integer> il = new List<Integer>();
    List<Object> ol = new List<Object>();
    copy(il, ol);

    Sometimes we are not interested in reading or writing elements, so we can say:

    List<*> list_of_unknown_type = ...;

    Then we can only use methods like size() on list_of_unknown_type.

  5. Re:Definitely a bug! by elflord · · Score: 5, Interesting
    Generics are at best a trade-off: compile-time type safety in exchange for less readable code.

    Given the choice between explicitly using a parameter, and using a nebulous "Object", I'd say that the template code is easier to read, because the parameter conveys more meaning than the word "object" (which offers no clue about what "type" is being used)

    Where C++ has no safety without generics, Java has runtime safety.

    Wrong. See dynamic_cast.

    As for readability, C++ has two major benefits over Java: a preprocessor and typedefs

    Shows how much you know -- you've named what are arguably two of the most botched legacy features of C++.

    Without at least one of these features, generics make code almost unreadable.

    This is not true. What makes code difficult to comprehend is complexity (allocaters, classes with several parametrised types, etc). Fortunately, C++ offers features that make complexity manageable (though typedefs don't deal with templates as well as they should)

    (I say mostly, because using STL with threads in cross-platform development is a recipe for disaster

    No, naively assuming that every STL implementation on every platform is thread safe is a recipe for disaster. Well, duh! The same is true even for straight C code -- you need to use thread safe versions of the library functions.

  6. Generics more readable by AT · · Score: 4, Interesting

    Huh? Generics make code more readable!

    When using non-generic containers in Java, you are usually forced to make a cast when accessing its members. For example:

    String s = (String) list.get(0);

    It gets worse if you are making multiple calls, because you usually need parentheses to bind the cast:

    String s = ((Foo) list.get(0)).fooMethod();

    However, with generics, you don't have to write the cast, because the type is implied. The bytecode is the same, but the code is much clearer:

    String s = list.get(0).fooMethod();

    Tell me how that is less readable. Anybody who thinks generics are unreadable is probably thinking of the worst C++ template abuses, needless complexity, and obscure syntax. Thankfully, Java generics are simple and clear.