Adam Lally wrote:
On Mon, Aug 10, 2009 at 9:00 PM, Marshall Schor<m...@schor.com> wrote:
Here's a new thread to discuss just one particular issue - a generics
tradeoff.
In other posts, people have expressed misgivings about letting users
"downcast" List<someType> to List<someSubType>, if it cannot be
*guaranteed* at compile time that this is valid.
Here's a simple example, for instance, using two built-in Java classes:
Number
Integer (a subtype of Number)
If we have a method which returns a List<Number>, and you happen to know
it only contains Integers, and you want to use a for-each on it with a
method that only exists in the Integer class, you have to do manual
casting within the loop.
An alternative might have been to do:
List<Number> numbers = ...;
List<Integer> int_version = numbers; // not allowed, gives compile error
So once we're given the "numbers" object, as far as I can see, we're
stuck with its typing. (Please tell me if I'm wrong here).
I see that there is a trade-off between specifying return types as
specific types, and specifying them as T extends X, and letting the user
specify a possibly incorrect downcast. The tradeoff on the plus side is
that the user gets to write the new style for-each loops, and have code
without casts inside loops, etc., and on the minus side, the user when
doing this gets that warning about the possibility that at runtime a
casting error could be thrown. But of course, that same casting error
could be thrown in restricted style, too, at the point of the explicit
user cast.
I'll probably stop trying to convince others if they continue to feel
that the tradeoffs here should be in the direction of returning only
specific types (disallowing users from specifying downcasting in that
manner), versus using types of the form T extends X,
which allows users to specify downcasting.
I'd be interested in any literature pointers discussing this trade-off
issue, if anyone has good ones :-)
One other way to look at this - why are Collections any different than
methods that return single elements? If I have a method
Number getNumber()
and I "know" in some situation that the Number is really an Integer,
should I be able to call:
Integer x = getNumber()?
Normally such a thing is not allowed without an explicit cast. And
for me at least I just take that for granted as part of what a
strongly-typed language does, so it's very bizarre to think of it not
doing that.
Lets say we have an interface Box{Number getNumber()}
then we could have a class BoxImpl implements Box{Integer getNumber(){...}}.
Now I only would have to cast once
Box box = ...;
BoxImpl boxImpl = (BoxImpl) box;
now
Integer number = boxImpl.getNumber()
would work. Sure if you do the same for CAS and CASImpl
you safe lots of casts.
The same does not work for a getNumbers which
returns a List<Number> or Iterator<Number>
without also allowing down casting.
Jörn