Follow Slashdot stories on Twitter

 



Forgot your password?
typodupeerror
×
Java Programming IT Technology

Sun to Add Variance to Java in 1.5? 55

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."
This discussion has been archived. No new comments can be posted.

Sun to Add Variance to Java in 1.5?

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

    Thanks
    • 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
    • An introduction explaining the basics of variance will be made available soon, probably within a day or two.
    • by Anonymous Coward
      I'm all for variance because it is complicated and ugly. C++ is complicated and ugly and it looks like Java and C# will move even further in that direction.

      Features like these will only hasten the move towards dynamically typed languages like Python, Smalltalk, Ruby, and CLOS.

      Dynamic typing may some dangerous, but the main thing that static typing prevents: calling a function that doesn't exist, happens in code about as often as dereferencing a null pointer. We don't see people shoveling syntax and stat
  • Definitely a bug! (Score:3, Insightful)

    by Twylite ( 234238 ) <twylite.crypt@co@za> on Monday June 02, 2003 @07:09AM (#6094638) Homepage

    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.

    • Re:Definitely a bug! (Score:5, Interesting)

      by DeadSea ( 69598 ) * on Monday June 02, 2003 @07:27AM (#6094750) Homepage Journal
      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;
      }
      • Re:Definitely a bug! (Score:3, Informative)

        by rlowe69 ( 74867 )
        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 [eclipse.org] compiler because toArray(s) returns Object[]. Instead it prefers:


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

        • Of course, this would be much better (you don't need the array length to be the size of the vector, it just needs to know what class it is):

          return (String[]) vector.toArray(new String[0]);

          or even

          private static final String dummy[] = {}; ...
          return (String[]) vector.toAyyar(MyClass.dummy);
          • Nice, I will definitely use that. Thanks.
          • It's true that it doesn't need to be of that size, but you're going to create a wasted object if you do it this way.

            toArray() will use the array given unless it's too small, so it's more efficient (and not any harder on the eyes or programmers fingers) to use an array of length vector.size().
      • Re:Definitely a bug! (Score:4, Informative)

        by j7953 ( 457666 ) on Monday June 02, 2003 @02:12PM (#6098309)

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

        • That's what I hate about Java's collections API. If it's a list, and if it provides set() et. al., then why can't you use it? "Intentional" runtime errors like UnsupportedOperationException are just as bad as a ClassCastException. Generics is meaningless when classes don't obey their contracts.

          A List is a List, and it is modifiable. A new class, UnmodifiableList, which doesn't provide set() or add(), is the only answer.
    • by hummassa ( 157160 )
      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.
    • Re:Definitely a bug! (Score:4, Interesting)

      by scrytch ( 9198 ) <chuck@myrealbox.com> on Monday June 02, 2003 @10:40AM (#6096180)
      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.
      • Should read: ... The fact that Foo<Bar> is a subclass of Foo ...

        Wouldn't it be nice if any disallowed HTML were just passed through as literal text instead of being stripped out?
      • but... but...

        Foo<Bar> isn' a subtype of Foo (which in this context should be read Foo<Object>), is it? So why should it be a subclass?

        That would require covariance in the type parameter implying subtyping, and a clear counter-argument is
        void set_element(<param>). For Foo<Bar>, it accepts only Bar, but for Foo it accepts any Object. Thus, treating a Foo<Bar> as a Foo will cause runtime errors.

        Java has already made this mistake with arrays.

        They so should have done the Righ
    • Re:Definitely a bug! (Score:5, Interesting)

      by elflord ( 9269 ) on Monday June 02, 2003 @10:41AM (#6096189) Homepage
      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.

    • by AT ( 21754 ) on Monday June 02, 2003 @12:02PM (#6096868)
      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.
    • by iabervon ( 1971 )
      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 committ
  • Variance? (Score:3, Funny)

    by robkill ( 259732 ) on Monday June 02, 2003 @07:10AM (#6094644)
    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?
    • Re:Variance? (Score:4, Informative)

      by iabervon ( 1971 ) on Monday June 02, 2003 @02:27PM (#6098606) Homepage Journal
      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.
  • What is variance? (Score:5, Informative)

    by DeadSea ( 69598 ) * on Monday June 02, 2003 @07:15AM (#6094670) Homepage Journal
    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 [sun.com]:

    > 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 [mit.edu] from that thread.

    • The compatibility problem is that the arrays get it wrong.

      Given animals aliased to cats, it would be statically type safe for me to say animals[0]=new Dog();. But this causes a runtime error. Runtime errors on assignment!?! Array subtyping is NOT a feature (although I would have to think for a bit what to replace it with before removing it).
      • The variance proposal included in the JSR14 prototype also applies to arrays. This may be the alternative to current runtime-checked array covariance, that you are looking for. You can declare animals to be invariant:

        Animal[=] animals;

        In which case assigning an array of Cats to animal is a static type error:

        animals = new Cat[10]; // Compile-time error!

        Or you can declare it to be covariant in a statically checked way, by writing:

        Animal[+] animals;
        Cat[=] cats = new Cat[10];
        animals = c

  • How does this bug relate, technically, to RFE 4144488 [sun.com], 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.

  • by Ahe ( 102184 ) on Monday June 02, 2003 @10:28AM (#6096096) Homepage Journal
    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.
  • Links (Score:2, Informative)

    by bonniot ( 633930 )
    The research article presenting the theory of variance [kyoto-u.ac.jp].

    There is a discussion about this on Lambda the Ultimate [weblogs.com].

    These links don't require registration :-)

  • The variance extension now has a homepage at http://www.daimi.au.dk/~plesner/variance [daimi.au.dk].
  • Gee, sometimes one wants to know if an object could be considered as some other type. Hmmm, writing methods that don't need to know the concrete type until run-time. Perhaps Sun should consider looking at a mature OO programming language like CLOS aka Common Lisp Object System. Lisp solved many of these problems long ago. From my perspective, the real value of Java is proving the concept of byte size virtual machine code for run anywhere capability. The real cost savings for continued programming in Ja

I had the rare misfortune of being one of the first people to try and implement a PL/1 compiler. -- T. Cheatham

Working...