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."

23 of 55 comments (clear)

  1. Somebody understood something ? by IIEFreeMan · · Score: 2, Interesting

    I did not but I would be interested to learn (I know what generics are but not variance)

    Thanks

    1. Re:Somebody understood something ? by hummassa · · Score: 2, Informative

      kind of simple, really...

      covariance: CT: container ISA CQ: container iff T ISA Q; so you can assign each contained Q to a T inside a CT, i.e., Write a Superclass Value To The Subclass Container;

      contravariance: CT ISA CQ iff Q ISA T; so you can assign some T from a Q in CQ, i.e., Read a Superclass Value From the Subclass Container;

      bivariance or invariance: CQ ISA CQ iff Q ISA T and T ISA Q; basically, you can only read or write to/from some container Equivalent types (the same type, actually, in Java);

      ok? hope to have helped;

      Massa

      --
      It's better to be the foot on the boot than the face on the pavement. ~~ tkx Kadin2048
    2. Re:Somebody understood something ? by noselasd · · Score: 3, Funny

      >ok? hope to have helped; Yes, you contributed quite a lot to common confusion with thisone.

    3. Re:Somebody understood something ? by Hard_Code · · Score: 2, Informative

      Why was this modded funny? This was the explanation of variants that was necessary.

      And remember, if you vote on that bug you are NOT voting for generics. That has already been agreed upon. You are voting for adding "variance" to generics, which is explained in the parent post.

      --

      It's 10 PM. Do you know if you're un-American?
    4. 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...
    5. Re:Somebody understood something ? by fizbin · · Score: 2, Informative

      Minor correction:

      Contravariance means that you can unpack a Base from a list of Derived without casting.

  2. Definitely a bug! by Twylite · · Score: 3, Insightful

    Generics are at best a trade-off: compile-time type safety in exchange for less readable code. A poor trade-off at best.

    Java never has and never will suffer the catastrophic consequences of type casting that C++ can. Type casts are all subject to runtime checks, so that the worst possible result is that an exception will be thrown. Where C++ has no safety without generics, Java has runtime safety.

    As for readability, C++ has two major benefits over Java: a preprocessor and typedefs. Without at least one of these features, generics make code almost unreadable. Little wonder that developers new to C++ are very cautious about getting involved with generics, or that old hands know how long it has taken for the STL to become mostly stable (I say mostly, because using STL with threads in cross-platform development is a recipe for disaster).

    Java is starting to look very much like something designed by a committee. A pity, because at its core it is still a good thing.

    --
    i-name =twylite [http://public.xdi.org/=twylite], see idcommons.net
    1. 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;
      }
    2. Re:Definitely a bug! by scrytch · · Score: 3, Interesting

      Unfortunately, since Java's generics act solely through type erasure, you're still screwed -- all Java generics do is insert invisible casts into your code, with all the overhead you expect from that. Type erasure is overall a good thing -- the fact that Foo is a subclass of Foo is very useful, and lets you avoid many of the ugly traits hacks in C++, and it does give good hints to the compiler, but at the same time, lack of a typedef also removes many of the things that are still useful in traits classes, and all the extra casts you don't see still cost as much as the ones you write by hand.

      The current release of jsr104 will even create mysterious ClassCastExceptions in some cases because the type inference is unsound. The documentation even warns of being able to do invalid casts (e.g. a String to a JFrame), which casts doubt on the safety of the complier. If that's the case, you can be sure that the jsr104 compiler is going to have one or more of its features axed before it makes it into tiger.

      --
      I've finally had it: until slashdot gets article moderation, I am not coming back.
    3. 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.

    4. Re:Definitely a bug! by iabervon · · Score: 2, Insightful

      The only way in which generics make code less readable is the awful angle brackets; otherwise it's a bit more verbose but no less clear, and verbosity has been an aspect of Java from the beginning.

      In C++, the reason people are scared of templates is that they're actually quite complicated, with historical stability problems and continuing unexpected behavior. Java only supports the more obvious cases.

      Java has been designed by committee from the start, but it's always been an extremely conservative committee; they only include features that a lot of people agree on and of which there are working implementations which have been tested enough to verify that the feature behaves as expected. They're also perfectly happy to not add a feature if it would cause problems, or to send it back for more discussion. C++ has had a lot of problems due to idealism and abstract discussion.

      It is significant that, in working on generics and variance, they've gone through the entire Collection library and considered how it should be modified to support all existing code while giving benefits to new code.

    5. Re:Definitely a bug! by rlowe69 · · Score: 2, Informative
      I don't know what compiler you are using, but your example

      public String[] getStrings(){
      String[] s = new String[vector.size()];
      return vector.toArray(s);
      }
      is not liked well by the Eclipse compiler because toArray(s) returns Object[]. Instead it prefers:

      public String[] getStrings(){
      String[] s = new String[vector.size()];
      return (String[])vector.toArray(s);
      }
      --
      ----- rL
    6. Re:Definitely a bug! by j7953 · · Score: 3, Informative

      You probably know this, but you usually don't want to return your internal list variable:

      public List getStrings() {
      return Collections.unmodifiableList(list);
      }

      (I haven't looked at Java's proposed generics yet, so I don't know how that would look with generics. I think that you might have to cast the result of unmodifiableList since by default it returns a List of Objects, not a List of Strings.)

      --
      Sig (appended to the end of comments I post, 54 chars)
  3. Variance? by robkill · · Score: 2, Funny

    I assume the correct term is Variants. I realize this is "leading edge" of java development, but are there any links that don't require being a member of the Java Development Consortium?

    --
    DMCA - Chilling free speech since 1998.
    1. Re:Variance? by iabervon · · Score: 3, Informative

      Nope, actually "Variance". The idea is that sometimes you need to know that something is exactly of some type, sometimes you need to know that something is "at least" of some type (i.e., equal or a subtype), and sometimes you need to know that something is "at most" of some type.

      Say you have a List, and you want to do:

      Number num = list.get(0);

      In this case, you need to know that the list contains elements which are Number or a subtype of Number, so you declare that you're taking a List<+Number>

      If you want to put a Number into the list, you need to know that the list can contain Numbers, which means that it has to be a list of "at most" Numbers (i.e., it is not a List of something more specific, which would not accept a Number). You thus declare that you're taking a List<-Number>.

      If you're going to do both, you require that the list contain nothing that's not a Number and that it be able to contain anything that is a Number, so you declare it to be List<=Number> (the = is optional in this case).

      If you don't care what type the elements are, you can use List<*>, rather than the equivalent List<+Object> (a list which contains Objects and subtypes; unrestrictive, since everything that's not a primitive type is a subtype of Object). This is somewhat clearer, since it means that you don't care at all.

      Of course, actual code is more likely to use type variables rather than Number; sort(), for instance, takes a List which is exactly of some unspecified type and a Comparator which does not require anything more specific than that type.

      Variance is a neat idea, but what's the rush? The issue is dealing with arrays. Traditional arrays require that a variable of Number[] get a value of at least Number[] (i.e., +Number in the new syntax), but they allow you to store a Number in the array, even if the array is actually of a subtype of Number; if it doesn't fit, you get a runtime exception. However, the extra type information for generics isn't around at runtime, so nothing can stop a List<Number> from being stored into an array of List<Double> which has been passed into a method which takes an array of Object (at compile time, it is an array of Object getting a List<Number>, at runtime, it is an array of List getting a List, but then a[0].get(0) might be an Integer not a Double like it's supposed to be). So the idea is to get a version of arrays like the variance-using Lists above into the language to be used with generics, which implies including variance at the same time as generics, so that unsafe arrays mixed with generics can be prohibited.

  4. 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.

  5. Insightful? Come on! by hummassa · · Score: 3, Insightful

    Ok. This is my first real drooling mad rant. Forgive me.

    [rant]
    about C++ casting (covariant model of generics): old-style casting was never of real use. use new_style_casts(x) and you have run-time checking, too. other stuff said about this is C++ ignorance.
    [/rant]

    ohboy, I had to get it off my chest.

    --
    It's better to be the foot on the boot than the face on the pavement. ~~ tkx Kadin2048
  6. Relation to covariant return types? (4144488) by valstadsve · · Score: 2

    How does this bug relate, technically, to RFE 4144488, which is pretty high on the vote count already? It seems they are requesting pretty similar stuff, so I'm curious if this is a tactical move to ensure the tiger is variant. Should we vote for both, or just this one?

    I want both of them, anyway. Good luck.

    --
    -- Wake up and XML the Java
    1. Re:Relation to covariant return types? (4144488) by gafter · · Score: 3, Informative

      No relation at all. That is for covariant
      return types on methods, this is for
      covariant (and contravariant) generic type
      parameters.

  7. Thank you. by hummassa · · Score: 2, Funny

    Now I have to wipe clean my keyboard, mouse, and work desktop machine 'cause you made me laugh while drinking my sugary black tea.

    It's confusing, yes, but... it's not my fault. I just tried to make it more or less more more or less confusing!! :-)

    bye

    --
    It's better to be the foot on the boot than the face on the pavement. ~~ tkx Kadin2048
  8. 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.

  9. 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.

  10. Links by bonniot · · Score: 2, Informative
    The research article presenting the theory of variance.

    There is a discussion about this on Lambda the Ultimate.

    These links don't require registration :-)