TimurMahammadov / google-collections

Automatically exported from code.google.com/p/google-collections
Apache License 2.0
0 stars 0 forks source link

Apply consistent policy about generics parameters of returned types #77

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
The Functions class includes these methods:

static <E> Function<Object,E> constant(E value)

static Function<Object,Integer> toHashCode() 

static <E> Function<E,E> identity() 

static <F> Function<F,String> toStringFunction() 

The constant() and hashCode() methods could let you specify the type of the
function input:

static <E, F> Function<F,E> constant(E value)

static <F> Function<F,Integer> toHashCode() 

We must decide whether to include the extra generic type parameter in
methods like those. Once we decide on a policy, we should review the code
and make sure it follows that policy.

Original issue reported on code.google.com by jared.l....@gmail.com on 9 Jun 2008 at 8:13

GoogleCodeExporter commented 9 years ago
my write-up (sorry this is redundant in places to the existing bug description)

This issue appeared settled a few months ago but I still have extreme misgivings
about it.  We could really use your input.  I apologize to everyone who 
participated
in the previous discussion and hoped it was settled.  I just can't make the 
change
requested in good conscience without trying one more time.

The issue applies to many, MANY methods of our collections API.  This is NOT a 
small
change we're talking about here.  I will, however use just one small example.

What should the method Functions.constant("here we go again") return?

(a) a Function<Object, String>:

    public static <T> Function<Object, T> constant(T constant) { ... }

(b) it should accept arbitrary type parameters F and T return Function<F, T> 
(in our
example, T can only be Object or String):

    public static <F,T> Function<F, T> constant(T constant) { ... }

Essentially, choice "a" is the *accurate* one; a constant function *is* capable 
of
accepting any input of type Object, and it *does* produce a String.  This is the
simpler approach.

The arguments for choice (b) involve a sort of flexibility.  If the user would 
rather
get the result of constant("x") as a Function<FooBar, Object> than a 
Function<Object,
String>, why not let them?  "What's the harm?"  After all, you're free to take 
the
result of a String-returning call and assign that to an Object any old time, so 
why
shouldn't this work the same?

Now that you hopefully understand the question...

I strongly prefer option (a).  My reasons are:

- I don't want to have to change dozens of our API methods to make them more
complicated.  Generics is already a very dicey business.

- Type inference does not work as well in practice as in theory.  Right now we 
have
8,790 occurrences in google3 of code using an explicit type parameter in a 
method
call, like 'Functions.<Number>constant(3)'.  If we make this change, these will
become 'Functions.<Number, Number>constant(3)'.  To me, this is completely 
disgusting.

- No one *should* ever need this kind of flexibility!  As long as APIs are 
defined
correctly, using the "PECS" principle (producer extends, consumer super), 
everything
is fine.  For example I recently made a seemingly innocuous change that broke a 
few
callers because they had methods to accept "Predicate<String>".  When they fixed
those to Predicate<? super String>, the problem went away again.  I know this is
ugly, but it's simply the way Java generics works, and we can't fix that in a
library, and we shouldn't be trying to.

- If someone does need this kind of flexibility, they can always just cast!  
True,
they have to suppress a warning, but they can do it.  We can _consider_, 
although I'm
not certain of this, continuing to provide "logical upcast" methods for each of 
our
types, that would let you "cast", for example, an Iterator<String> to an
Iterator<Object> warning-free.  This should be warning-free; but then, it 
shouldn't
be necessary.

- Again, this added "flexibility" which we don't need is not free.  It does 
raise the
complexity and I am positive that it will increase users' troubles with type
inference which is already an extremely dodgy business as it is.

- By making this change, we'll be encouraging people all over the world to 
continue
forming their method signatures incorrectly.  We'll be sanctioning the practice 
of
ignoring wildcards and PECS.

- We'll also find users doing things like passing functions through an identity
transformation just so that they can change the type params, which is gross; 
dancing
around generics problems shouldn't result in runtime cost!

I'll stop here.  Jared's now going to present the case for the opposition.  
Please
help us settle this debate.

Original comment by kevin...@gmail.com on 10 Jun 2008 at 7:15

GoogleCodeExporter commented 9 years ago
oh: for those external to google who have no idea what I meant when I said "in
google3", I'm just referring to our source repository.  I'm able to run searches
across all google source code, and I found that contrary to what the Java 
Generics
designers had desperately hoped for, it has proved to be quite common to have to
supply the Explicit.<Type>parameters().

Original comment by kevin...@gmail.com on 10 Jun 2008 at 7:22

GoogleCodeExporter commented 9 years ago

Original comment by kevin...@gmail.com on 6 Apr 2009 at 8:11