Why use a wild card capture helper method?

Referring to : Wildcard Capture Helper Methods

It says to create a helper method to capture the wild card.

public void foo(List<?> i) { fooHelper(i); } private <T> void fooHelper(List<T> l) { l.set(0, l.get(0)); }

Just using this function below alone doesn't produce any compilation errors, and seems to work the same way. What I don't understand is: why wouldn't you just use this and avoid using a helper?

public <T> void foo(List<T> l) { l.set(0, l.get(0)); }

I thought that this question would really boil down to: what's the difference between wildcard and generics? So, I went to this: difference between wildcard and generics. It says to use type parameters:

1) If you want to enforce some relationship on the different types of method arguments, you can't do that with wildcards, you have to use type parameters.

But, isn't that exactly what the wildcard with helper function is actually doing? Is it not enforcing a relationship on different types of method arguments with its setting and getting of unknown values?

My question is: If you have to define something that requires a relationship on different types of method args, then why use wildcards in the first place and then use a helper function for it?

It seems like a hacky way to incorporate wildcards.

-------------Problems Reply------------

In this particular case it's because the List.set(int, E) method requires the type to be the same as the type in the list.

If you don't have the helper method, the compiler doesn't know if ? is the same for List<?> and the return from get(int) so you get a compiler error:

The method set(int, capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (int, capture#2-of ?)

With the helper method, you are telling the compiler, the type is the same, I just don't know what the type is.

So why have the non-helper method?

Generics weren't introduced until Java 5 so there is a lot of code out there that predates generics. A pre-Java 5 List is now a List<?> so if you were trying to compile old code in a generic aware compiler, you would have to add these helper methods if you couldn't change the method signatures.

You are correct that we don't have to use the wildcard version.

It comes down to which API looks/feels "better", which is subjective

void foo(List<?> i)
<T> void foo(List<T> i)

I'll say the 1st version is better.

If there are bounds

void foo(List<? extends Number> i)
<T extends Number> void foo(List<T> i)

The 1st version looks even more compact; the type information are all in one place.

At this point of time, the wildcard version is the idiomatic way, and it's more familiar to programmers.

There are a lot of wildcards in JDK method definitions, particularly after java8's introduction of lambda/Stream. They are very ugly, admittedly, because we don't have variance types. But think how much uglier it'll be if we expand all wildcards to type vars.

I agree: Delete the helper method and type the public API. There's no reason not to, and every reason to.

Just to summarise the need for the helper with the wildcard version: Although it's obvious to us as humans, the compiler doesn't know that the unknown type returned from l.get(0) is the same unknown type of the list itself. ie it doesn't factor in that the parameter of the set() call comes from the same list object as the target, so it must be a safe operation. It only notices that the type returned from get() is unknown and the type of the target list is unknown, and two unknowns are not guaranteed to be the same type.

Category:java Views:4 Time:2018-11-29

Related post

Copyright (C) dskims.com, All Rights Reserved.

processed in 0.162 (s). 12 q(s)