Forum Stats

  • 3,853,788 Users
  • 2,264,269 Discussions
  • 7,905,444 Comments

Discussions

Suggestions

843793
843793 Member Posts: 41,732 Green Ribbon
edited Jul 22, 2002 10:01AM in Generics
1. Used to be that this would refuse to compile:

class Foo<A,B extends A> {}

because a type variable B couldn't be bound by another type variable E. Don't know if it still works like this but I think the above really should be allowed...e.g. consider

interface List<A>
{
public <B extends A> void addAll(List<B> items)
}

which is more flexible than

interface List<A>
{
public void addAll(List<A> items)
}

I've implemented this in my own generic-java-to-pure-java source translator, but sadly it doesn't support parametric methods etc. so it would be nice to add it to GJ...

2. Be nice if covariant/contravariant subtyping were allowed in cases where they were safe (without runtime checks), e.g. for

interface Iterator<E>
{
public boolean hasNext();
public void remove();
public E next();
}

Iterator<String> could safely be a subtype of Iterator<Object> (no method in Iterator<E> accepts an E), but not vice versa, and

interface Handler<E>
{
public void handle(E item);
}

Handler<Object> should be a subtype of Handler<String>. For a class/interface which both takes and returns items of the same type variable, invariance in that type variable is necessary, as it is if you have a non-final field (a final field effectively only returns values, so allows the object to be assigned covariantly as per the Iterator above). If only 'private' fields were really private (could only be accessed by the same object not the same class) then we could ignore them for purposes of allowing co/contravariance, but never mind...

This additional flexibility might make ensuring casts are safe harder (i.e. more casts would have to be declared unsafe), so existential types might be useful too, but that's another story...

--Alan

Comments

  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    1. Why not try it with the latest generic compiler? I think the code you show will compile now.

    2. I don't like the idea because it will restrict the methods that interfaces and classes that extend and implement the interfaces can declare. For example, a class that implements your Iterator<E> class cannot declare a method that takes an E. Even worse, adding a method to Iterator<E> that takes E as a parameter could cause code that uses the covariance of Iterator<E> to fail to compile. This is inconsistent with the rules of Binary Compatibility in the JLS.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    (2) is dubious whenever the collection has both read and write access. However, if Java supported read-only references (bug 4211070), this would become possible.

    When giving a read-only Collection<E>, the only constraint is that everything you read from it must be an E, so a Collection<T extends E> is acceptable. Covariance.

    When giving a write-only Collection<E>, the only constraint is that it must be able to accept you writing Es, so a Collection<T> where T is a parent of E is acceptable. Contravariant.

    But at present all references are read-and-write, so you have to pass them invariantly, as Collection<E>.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    Read only references? You don't have a problem adding functionality which is tied to keywords as opposed to class definitions?

This discussion has been closed.