Returning a bounded wildcard type

M

markspace

So we've gone around about bounded wildcard types here on cljp. I've
got a method where it seems natural to return a references type like this:

(Note: none of this code was syntax checked.)

Type<? extends Bound> someMethod() {....

Normally, this would be bad, or at least dubious. However, what I've
got is a situation where "Bound" is little more than a marker type (for
now) and Bound is designed to be extended. To be a bit more clear:


public interface MyMap {

class Node {}

List<? extends Node> getNodes();

}


And what I'm actually doing is:


public class MyMapImpl implements MyMap {

List<MyNode> nodes;

List<? extends Nodes> getNodes() {
return Collections.unmodifiableList(
nodes );
}

private static class MyNode extends MyMap.Node {}

}


So, the return type of getNodes() appears to match pretty well with it's
intended purpose. Not only does the compiler prevent you from adding
types to the List returned by getNodes(), but the runtime does as well.

I'm just wondering if anyone sees problems here. Maybe some needed
flexibility in the return type of getNodes() that'll bite me later?

I haven't gone any further than this with the design, I just thought I'd
put this up for discussion. Have fun!
 
T

Tom Anderson

public interface MyMap {
class Node {}
List<? extends Node> getNodes();
}

Why not:

public interface MyMap<N extends Node> {
List<N> getNodes();
}

?

tom
 
L

Lew

Tom Anderson wrote:

The reasoning pundits offer against this is that it pushes the responsibility
for the subtyping off on the client and is much, much less clean in practice
than what those pundits, and tom below, recommend instead.

Every programmer I've known to attempt to use wildcards in a return type, at
least bounded ones, finds themselves in trouble before very long.
Why not:

public interface MyMap<N extends Node> {
List<N> getNodes();
}

?

That's the approach that Josh Bloch, Brian Goetz and others recommend.

When my aforementioned associates switched to following that advice, their
issues induced by the return of (bounded) wildcards vanished.

The recommended syntax, as exemplified in tom's response, works so well that
there should be no need to consider the (bounded) wildcard return type. The
bounded wildcard return is, of course, legal syntax, but it makes far too weak
a declaration about the types involved.
 
M

markspace

That's the approach that Josh Bloch, Brian Goetz and others recommend.


Thanks for the advice guys. This is just a personal project I'm messing
around with, so it was just my own design.

The idea was that the class MyMapImpl shouldn't need to be subclassed.
It should handle having it's implementation removed and replaced by a
different one, with out any clients being any wiser.. I think in
retrospect I'll go with this instead:

public interface MyMap {

class Node{
}

List<Node> getNodes();
List<Node> getAdjecientNodes( Node node );
float estimateCost( Node startNode, Node endNode );

}

since that doesn't use parameter types and still gets the job done with
out using wild cards. I have to change a couple of types in my
implementation, but I can still put a subclass of Node in a List<Node>
without doing anything risky, programmatically. I think this is the
better way to go.
 
L

Lew

markspace said:
I think in retrospect I'll go with this instead:

public interface MyMap {

class Node{
}

List<Node> getNodes();
List<Node> getAdjecientNodes( Node node );
float estimateCost( Node startNode, Node endNode );

}

since that doesn't use parameter types and still gets the job done with
out using wild cards. I have to change a couple of types in my
implementation, but I can still put a subclass of Node in a List<Node>
without doing anything risky, programmatically. I think this is the
better way to go.

Your solution is fine, but I'd like to discuss the difference between
'List <Node> nodes', 'List <? extends Node> nodes' and
'class Foo <N extends Node> { List <N> nodes; ... }'
(or the method-level equivalent,
'<N extends Node> void foo( List <N>

Your approach, 'List <Node>', claims that the 'List' homogeneously contains
'Node' elements, but each one could be of a different subtype of 'Node'. The
other two claim that the 'List' is homogeneously of some subtype of 'Node',
possibly 'Node' itself. You can read from or write to the 'List'.

'List <? extends Node>' claims that the element type is of some anonymous
subtype of 'Node'. You can read from the 'List' and reliably treat the
elements as 'Node', but you cannot insert into the 'List'. You cannot readily
make claims about the relationship between different "?" expressions, i.e.,
captures of 'Node'.

The last approach, 'List <N extends Node>', claims that the element type is of
a specific subtype 'N' of 'Node, that type determined by the client expression
that uses the class or method. You can read from or write to the 'List'. All
expressions within the class or method that refer to 'N' refer to the same type.

So given

public class Foo
{
public List <? extends Node> perform() {...}
public List <? extends Node> execute() {...}
}

you cannot know the relationship between the return element types of the two
methods within a specific 'Foo' instance, except that they are both possibly
different subtypes of 'Node'. But given

public class Foo <N extends Node>
{
public List <N> perform() {...}
public List <N> execute() {...}
}

you know for sure that both methods in the same instance will return the same
subtype of 'Node'.

For your purposes you have determined that it is only necessary to claim that
the 'List' contains 'Node', ergo you don't need to use 'extends Node' in your
type parameter.
 
T

Tom Anderson

Your solution is fine, but I'd like to discuss the difference between
'List <Node> nodes', 'List <? extends Node> nodes' and
'class Foo <N extends Node> { List <N> nodes; ... }'
(or the method-level equivalent,
'<N extends Node> void foo( List <N>

I can't BELIEVE you forgot <? extends Collection<? extends Node>>!

I have no idea if you can even write that.

tom
 
L

Lew

Tom said:
I can't BELIEVE you forgot <? extends Collection<? extends Node>>!

I have no idea if you can even write that.

My purpose was not to completely explain everything there is to know
about generics, but to focus on one relatively simple aspect. Your
suggestion is understood by extending the principles embodied in the
simpler <? extends Foo> case.

And yes, your suggestion is legal, if somewhat corner-casish.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top