Re: generics:< ? >vs.< T >
Trying to post through the old Google Groups interface to see whether
thread disruption occurs here as well.
On Mar 11, 12:17 am, Lew <no...@lewscanon.com> wrote:
Robert Klemme wrote:
Lew wrote:
But for the type of thing that you cited upthread, just a <T> is usual=
ly
better than a bounded wildcard type. Unlike types themselves, where th=
e
advice is to generalize the declared type, for generic type parameters
it's often better to specify.
Hmm... Interesting point of view. I'll have to ponder that. My generic =
- err -
general position on this is to make type parameters as general as possi=
ble.
That's a very bad approach. Type parameters should assert the type
relationships you need, not be "as general as possible".
It's the same rule why we do doX(List l) instead of doX(ArrayList l),
i.e. we use the most general type that is sufficient to do what the
method is supposed to do. Similarly we use doX(List<? extends Foo> l)
instead of doX(List<Foo> l) so the method can be applied to a wider
range of arguments.
The trouble is that generalizing type assertions weakens them. <? exte=
nds
Foo> is a much weaker assertion than <Foo>,
That's exactly the purpose of using bounds, generalization. It shares
this purpose with another construct: interfaces. I'm afraid, I still
haven't understood why you seem to generally prefer unbounded types
over wildcards.
and disallows certain operations
(puts, specifically).
Well, but the rule I mentioned earlier (bounds should be determined by
usage of a type inside the method) applies. There are basically three
cases
1. Reading from a parametrized type => use "extends"
void doX(List<? extends Foo> l)
2. Writing to a parametrized type => use "super"
void doX(List<? super Foo> l)
1. + 2. = 3. => do not use bounds
void doX(List<Foo> l)
It also doesn't let you match types:
public void foo( Bar <? extends Baz> bar, Qux <? extends Bax> qux =
);
Is this a typo? Did you mean "Qux <? extends Baz>"?
allows you only very limited conclusions about the type relationships bet=
ween
the base types of the two arguments. You cannot assert them to be prov=
ably
the same type. Eliminating the wildcard allows the compiler to see the=
guarantee.
There is another way (assuming typo) which also eliminates the
wildcard - but only from the argument list:
public <X extends Baz> void foo( Bar<X> bar, Qux<X> qux );
This method is more useful than
public void foo( Bar<Baz> bar, Qux<Baz> qux );
because it is applicable to a wider range of arguments without any
logical or implementation change. Of course it depends on the usage
(see above) - if there is read and write access (case 3) then of
course you must stick with the version without wildcards.
You can even leave in a wildcard and allow different types with a
relationship
public static <X extends Baz> void foo2(Bar<X> bar, Qux<? extends X>
qux) {
qux.getMember().baz();
bar.setMember(qux.getMember());
}
assuming parametrized "member" in all classes and a method with the
lowercase class name.
And I apply it also to generic parameters of methods even though I read=
ily
admit that they make things a bit complicated at times (complicated at =
least
for the implementer, but since I like puzzles like this it doesn't puzz=
le me
too much). If things get too complicated for the user of such a method =
I'd
definitively rethink the approach. There you have another rule of thumb=
of
mine: easy of use is more important than ease of writing (i.e. interfac=
e
matters).
The rule of thumb is: "Generics should assert the type relationships need=
ed
for the code to work."
.... and they should be as general as possible.
But whatever. I wasn't writing code to copy, I was writing code to lea=
rn
from. Now they can learn from your additional comments. That plus l=
ogic
specific to their problem will make a program.
I do hope that people learn and not mindlessly copy. Unfortunately
there seems to be a significant portion of people around who believe
the do not need to think themselves if they can copy "ready made" code
from somewhere. I even saw people mindlessly copying their own code
over and over again instead of refactoring common parts into functions
or methods. Sigh!
Kind regards
robert