Johannes
Johannes

Reputation: 2121

return type of generic methods

If I have a method, for instance

public INode getNode(final int offset);

I assume it doesn't add something to make the method return type generic, for instance:

public <T extends INode> T getNode(final int offset);

Or did I miss something? I think generic return types are only of value if one of the parameters is of the same type (or a super/subtype)?

Upvotes: 3

Views: 399

Answers (2)

meriton
meriton

Reputation: 70564

public <T extends INode> T getNode(final int offset);

Not only does this not provide any additional information to the caller, but is outright dangerous: The only way to implement that method signature is to use an unchecked cast, which can not be type safe, because a method's type parameters are specified by its caller (explicitly or implictly through type inference), and the type parameters aren't available to this method's implementation. For instance, consider the following program:

class NodeCollection {
    private INode[] nodes = new INode[42];

    public <T extends INode> T getNode(final int offset) {
        return (T) nodes[offset];
    }

    public <T extends INode> setNode(final int offset, T node) {
        nodes[offset] = node;
    }
}

class ANode implements INode {}
class BNode implements INode {
    void foo();
}

public class Test {
    public static void main(String[] args) {
        NodeCollection nc = new NodeCollection();
        nc.setNode(0,new ANode());
        BNode b = nc.getNode(0); // throws ClassCastException (sic!)
    }
}

Best practice: Don't use an unchecked cast, unless you are really sure it'll be type correct at runtime.

I think generic return types are only of value if one of the parameters is of the same type (or a super/subtype)?

There are more cases, for instance:

public <T> T getFavorite(Class<T> clazz) {
    return clazz.cast(favorites.get(clazz));
}

or

interface List<E> {
    E get(int index);
}

or the examples in Colin's answer, where the type variable merely appears as type parameter in the return type, which is acceptable due to type erasure.

Edit:

I think there's no type save way if one wants to cast to the exact type of node (instead of instanceof has to precede it)

Of course there is, it's called visitor pattern.

Upvotes: 4

Colin Hebert
Colin Hebert

Reputation: 93157

In the example you give, it doesn't really add any value except forcing the developer of the implementation to cast the return value (in T). (Unless it has a way to get a T value, but for that it would need to call another method which returns T, so you're just moving the cast a bit further.

So not really a good idea in the case you're showing us.


There are a few cases where the generic applied only to the return value can be useful. For example:

public static <T> Collection<T> generateCollection() {
    return new ArrayList<T>();
}

This allows you to create an object Collection of T without having to do any cast.

Or if you want the developer doing the implementation to cast his object (mostly works when the said object uses generics), example from Collections:

public static final <T> Set<T> emptySet() {
    return (Set<T>) EMPTY_SET;
}

Resources:

Upvotes: 1

Related Questions