Introduce Covariance/Contravariance at declaration site for Java 9 ?

Brian Goetz brian.goetz at oracle.com
Sat Oct 27 09:22:28 PDT 2012


This is definitely worthy of exploration.  And, the good news is, it can 
be entirely implemented using a JSR-308 checker -- so (at least 
initially) no javac changes are required to develop and validate the 
concept.  This fits nicely into the use of annotations as a means of 
capturing design intent, and enabling tools to verify design intent.

(Its bad enough we make these mistakes; its worse that some of these 
then cannot be corrected because of compatibility concerns.)

On 10/27/2012 6:19 AM, Remi Forax wrote:
> I've maybe found a solution :)
>
> First, it's not possible to let the compiler do the transformation
> automagically because
> in that case adding a default method to a function interface may break a
> lot of user code.
> A function interface that is inherently co/contravariant should be
> declared as such in its declaration.
>
> Removing the burden for the user to write wildcard is a nice goal, but
> it means that
> the Java type system will be inherently more complex and it may not
> worth to add such
> complexity for little benefit.
>
> The issue is that users that creates API forget to add wildcards, so the
> practical solution is to
> add a lint option to javac that warn user when they use a
> co/contravariant function interfaces
> without specifying wildcards.
> This solution doesn't change the type system so it can be implemented
> without pain and fear of corner cases.
>
> Here is the proposal:
> - adds two new type annotations (as defined by JSR308) in
> java.lang.annotation, Covariant and Contravariant,
> that applies on type variables. These annotations are not inherited.
> - add a new lint pass to javac that checks parameters of methods (not
> returns type, you should not use wildcards
> on return type). If a type of a parameter is a parametrized type with
> type variables annotated with Covariant
> (resp. contravariant), emit a warning is the parametrized type is not a
> ? extends X (resp. ? super X).
>
> so by example, the function interface Mapper will be declared:
>    interface Mapper<@Covariant U, @Contravariant T> {
>      public U map(T element);
>    }
> and Iterator and Iterable can be retrofitted like this:
>    interface Iterator<@Covariant T> { ... }
>    interface Iterable<@Covariant T> { ... }
> but ListIterator, that inherits from Iterator can not have it's
> parameter T declared as covariant
> because ListIterator defined methods add and set that takes a T as
> parameter
> (that's why annotations @Covariant/@Contravariant should be declared are
> not inheritable).
>
> now if in a class there is a method declared like this:
>    static <T, U> Iterator<U> mapIterator(Iterator<T> iterator, Mapper<U,
> T> mapper) { ... }
> the compiler will emit two warnings because the parameter iterator
> should be an Iterator<? extends T>
> and mapper should be a Mapper<? extends U, ? super T>.
>
> The only open question is does lint should accept to tag a type
> parameter with @Covariant/@Contravariant
> even if the type parameter appear in method of the interface at position
> it should not. C# does that.
>
> cheers,
> Rémi
>
> On 10/18/2012 09:25 PM, Kevin Bourrillion wrote:
>> FTR, I agree fairly strongly with everything Dan says here.
>>
>>
>> On Thu, Oct 18, 2012 at 12:20 PM, Dan Smith <daniel.smith at oracle.com
>> <mailto:daniel.smith at oracle.com>> wrote:
>>
>>     I think it's a good idea, at least worth serious consideration.
>>
>>     There would be no _requirement_ to design libraries in
>>     declaration-site-friendly ways, but the fact is we already have
>>     _lots_ of types that are inherently co-/contra- variant, and the
>>     "right" way to use those types is to always use a wildcard.  It
>>     turns into a mechanical transformation that obscures the code
>>     behind layers of wildcards and pointlessly punishes users if they
>>     mess up; it would sure be nice to remove that burden from clients
>>     of variant types.
>>
>>     Anyway, I can say it's on the radar.  But maybe we will conclude
>>     it's a horrible idea; or maybe other things will take priority.
>>
>>     —Dan
>>
>>     On Oct 15, 2012, at 6:24 PM, Joshua Bloch <josh at bloch.us
>>     <mailto:josh at bloch.us>> wrote:
>>
>>     > I believe that declaration site variance annotations are every
>>     bit as bad as use-site annotations.  They're bad in a different
>>     way--they force you to write idiosyncratic types because natural
>>     types don't lend themselves to fixed variance restrictions--but
>>     they're still bad. Providing both use and declaration site
>>     variance in one language is the worst of both worlds (unless
>>     you're trying to kill the language).
>>     >
>>     >     Josh
>>     >
>>     > On Mon, Oct 15, 2012 at 3:09 PM, Remi Forax <forax at univ-mlv.fr
>>     <mailto:forax at univ-mlv.fr>> wrote:
>>     > I've just read the presentation of Stuart Marks at JavaOne [1],
>>     > all examples after slide 32, the first one that use lambdas are
>>     not written correctly
>>     > because all method signatures do not use wildcards.
>>     >
>>     > Brian, I know that we will not be able to introduce
>>     covariance/contravariance
>>     > at declaration site for Java 8, so the solution we will deliver
>>     will be far from perfect
>>     > because nobody understand wildcards.
>>     > Is there a way to free Dan and Maurizio  enough time to
>>     investigate if
>>     > covariance/contravariance can be added to Java 9.
>>     >
>>     > Rémi
>>     > [1]
>>
>> https://stuartmarks.wordpress.com/2012/10/07/javaone-2012-jump-starting-lambda-programming/
>>
>>     >
>>     >
>>
>>
>>
>>
>> --
>> Kevin Bourrillion | Java Librarian | Google, Inc. |kevinb at google.com
>> <mailto:kevinb at google.com>
>>
>


More information about the lambda-libs-spec-experts mailing list