Forum Stats

  • 3,760,212 Users
  • 2,251,664 Discussions
  • 7,871,021 Comments

Discussions

What does the return type " <T> T" mean?

843793
843793 Member Posts: 41,732 Green Ribbon
edited Jun 12, 2010 11:09PM in Generics
Hi,

I've recently stumbled over a method in an interface I need to implement which looks like:
 <T> T methodName();
I've never seen such a strange return type, it would be great if somebody could take the patience and just explain short whats all this is about.
So ok the <T> is some generic universal type I guess, but whats about that single T after it?

Sorry for the dumb question.

Thank you in advance, Clemens
«134

Comments

  • brucechapman
    brucechapman Member Posts: 466
    Clemens,

    <T> is a type parameter whose scope is the method. T is the return type of the method.

    That particular interface method is probably an abomination.

    The method signature uses generic methods (it has type parameters local to the method). This one says the return type is whatever you specify it to be when you call it, or whatever you want it to be if you don't specify.

    for example
    Integer i = that.methodName()
    means the method will return an Integer. or
    Object x = that.<Double>methodName()
    means the method will return a Double.

    Of course this is all ridiculous because there is no way for the method to know what the required type is, so it cannot do what is asked.

    This voodoo magic can be used to avoid the caller having to cast the return result from a method that can return multiple types, where the caller knows what to expect in some way. However if the caller gets it wrong, you won't know till runtime when you will get a ClassCastException. This particular use of generic methods tends to suggest that the author of the method was highly incompetent with using generics.


    How this is supposed to work is that the generic methods type parameter can be used to infer relationships between the types of various arguments and the return type. For example [Collections.singleton()|http://java.sun.com/javase/6/docs/api/java/util/Collections.html#singleton(T)]

    If you see a generic method where the type parameter is only used for the return type, it is almost always an abomination. A case where it is valid is for example [Collections.emtyList()|http://java.sun.com/javase/6/docs/api/java/util/Collections.html#emptyList()] becuase an empty list is actually a list of whatever you want.

    If you told us what the method was supposed to do, we could determine whether it is in fact an abuse of the language or is valid.

    It may be that you can implement this method, but it is more likely that you are expected to perform some magic.

    Bruce
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    brucechapman wrote:
    This voodoo magic can be used to avoid the caller having to cast the return result from a method that can return multiple types, where the caller knows what to expect in some way.
    Mhh, the caller can certainly avoid explicitly casting the returned value; no cast at all won't pass byte code validation (assuming the required type is not a supertype of the upper bound).
    However if the caller gets it wrong, you won't know till runtime when you will get a ClassCastException.
    As opposed to getting it wrong with an explicit cast?
    This particular use of generic methods tends to suggest that the author of the method was highly incompetent with using generics.
    I fail to reach this conclusion.
    SomeType var = someMethod();
    // vs
    SomeType var = (SomeType)someMethod();
    Both lines of code indicate that if someMethod returns normally the returned object better be of SomeType. I'm sure an argument can be made for making the cast explicit/visible, but jumping to incompetence is a stretch.

    With kind regards
    Ben
  • brucechapman
    brucechapman Member Posts: 466
    The only way to implement this abstract method
     <T> T methodName();
    is for all execution paths to do one of the following:

    1. return null

    2. cause the compiler to issue an unchecked warning (optionally suppressing this warning) [(see JLS 5.5)|http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.5]

    3. throw an exception

    2 is not type safe. 1 and 3 imply a void method

    Hence my assertion that the author is not competent with generics.

    The correct thing to do is to pass an argument whose type also depends on T so that the code can use that information in some way to either return null or throw an exception when the return value is not of the expected type.

    An example of methods which would benefit from this treatment are in this class

    It this case the caller might know what particular subtype the element ought to be, but there are no guarantees they are correct. If you want that sort of 'wishful runtime typing' then don't use a statically typed language.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    Hi,

    Thanks for your answers - I simply cast the resturn value to <T> now and it seems to work.
    We got that interface at university ;)

    Thanks again, Clemens
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    brucechapman wrote:
    The only way to implement this abstract method
     <T> T methodName();
    is for all execution paths to do one of the following:

    1. return null

    2. cause the compiler to issue an unchecked warning (optionally suppressing this warning) [(see JLS 5.5)|http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.5]

    3. throw an exception

    2 is not type safe. 1 and 3 imply a void method

    Hence my assertion that the author is not competent with generics.
    Well, that's a nice leap of logic. There may very well be a protocol as to which types are returned when, a protocol which is separate from anything the Java compiler can reason about. An example of this would be object deserialization.
    The correct thing to do is to pass an argument whose type also depends on T so that the code can use that information in some way to either return null or throw an exception when the return value is not of the expected type.
    I thought the whole point of this was type safety? You won't get that due to type erasure, even with TypeLiterals a là guice -- an instance of List<Integer> can't be shown not to be a List<String>. If you'd be happy with just testing against the relevant Class (uh oh, unchecked warning..) then deserialization gets by without passing it in just fine.
    It this case the caller might know what particular subtype the element ought to be, but there are no guarantees they are correct.
    There are never any guarantees. javac is not Coq; when a Java compiler accepts code without warning that does not mean it's correct.
    If you want that sort of 'wishful runtime typing' then don't use a statically typed language.
    So are you calling anyone who has ever used reflection or (de)serialization incompetent as well? Isn't any downcast "wishful" runtime typing?

    With kind regards
    Ben
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    edited May 28, 2010 4:47PM
    BenSchulz wrote:
    brucechapman wrote:
    2. cause the compiler to issue an unchecked warning (optionally suppressing this warning) [(see JLS 5.5)|http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.5]
    Well, that's a nice leap of logic. There may very well be a protocol as to which types are returned when, a protocol which is separate from anything the Java compiler can reason about. An example of this would be object deserialization.
    Which still would require #2, an unchecked cast.
    I thought the whole point of this was type safety? You won't get that due to type erasure, even with TypeLiterals a là guice -- an instance of List<Integer> can't be shown not to be a List<String>. If you'd be happy with just testing against the relevant Class (uh oh, unchecked warning..) then deserialization gets by without passing it in just fine.
    Programmers understand that ClassCastExceptions can occur when they make an explicit cast. It's usually safe to assume that when you're not doing a cast, you won't get a ClassCastException.

    However, with code like this:
    public <T> T readObject() {
       return (T) readNextObjectFromStream();
    }
    
    //...
    String name = readObject();
    String address = readObject();
    Date dateOfBirth = readObject();
    You are essentially deliberately hiding type-unsafety from the caller. That's bad library design. Even if you don't suppress the unchecked warning, the compile warning is at the library method, not the caller method. But the ClassCastException would be generated at the CALLER, and that's not cool.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    endasil wrote:
    BenSchulz wrote:
    brucechapman wrote:
    2. cause the compiler to issue an unchecked warning (optionally suppressing this warning) [(see JLS 5.5)|http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.5]
    Well, that's a nice leap of logic. There may very well be a protocol as to which types are returned when, a protocol which is separate from anything the Java compiler can reason about. An example of this would be object deserialization.
    Which still would require #2, an unchecked cast.
    Absolutely, so what?
    I thought the whole point of this was type safety? You won't get that due to type erasure, even with TypeLiterals a là guice -- an instance of List<Integer> can't be shown not to be a List<String>. If you'd be happy with just testing against the relevant Class (uh oh, unchecked warning..) then deserialization gets by without passing it in just fine.
    Programmers understand that ClassCastExceptions can occur when they make an explicit cast. It's usually safe to assume that when you're not doing a cast, you won't get a ClassCastException.
    You are casting though, ergo you should not feel safe. When retrieving an element from a list you might get a CCE too, when retrieving an int from a list you might also get a NPE. None of this is explicit, it could happen anyways. People tend to be surprised for a couple of seconds and then they go "ahh, auto unboxing"; why should this be any different? Are the language designers incompetent too?
    [...]
    You are essentially deliberately hiding type-unsafety from the caller. That's bad library design. Even if you don't suppress the unchecked warning, the compile warning is at the library method, not the caller method. But the ClassCastException would be generated at the CALLER, and that's not cool.
    Why is that not cool? Is anyone with marginal understanding of the Java language going to expect the compiler to verify something that is not even part of the code? I'm reading from a stream of basically random objects, of course there'll be a cast there.

    All I'm doing is removing the redundancy, I see clear parallels to the Java 7 diamond operator.

    With kind regards
    Ben
  • brucechapman
    brucechapman Member Posts: 466
    Ben,

    The casting argument is irrelevant to this discussion. If the caller is expected to downcast to a specific type, then the method would have a return type of Object (or some other common super type of all possible return types). What this method has is a return type of whatever the caller wants. The only way an implementation can comply with that contract is the 3 means already discussed.

    In other words this signature could be tested by the following
    import java.util.Random;
    
    public class Test {
    
        public static class Impl {
            <T> T someMethod() {
                return null; // TODO replace with non trivial implementation
            }
        }
    
        public static void main(String[] args) {
            Random r = new Random(System.currentTimeMillis());
            Impl sut = new Impl();
            boolean alwaysNull = true;
            for(int i=0; i < 10000; i++) {
                if(r.nextBoolean()) {
                    String s = sut.someMethod();
                    if(s != null)alwaysNull = false;
                } else {
                    Test t = sut.someMethod();
                    if(t != null)alwaysNull = false;
                }
            }
            assert ! alwaysNull;
        }
    }
    can you come up with an implementation of Impl.someMethod() that always terminates normally with assertions enabled and doesn't compile with unchecked warnings?

    And if not how can you say that the author's use of generics is not highly incompetent?

    But its not necessarily fair for me to pose a programming challenge on you (especially one that I feel is impossible). So alternatively I'll let you propose some semantics for the OP's method signature, and possibly even a few sibling method signatures if necessary to elaborate, and I claim that I can write a better signature for someMethod, better in terms of capturing the semantics and competence with generics.

    If this is a university course assignment, then we need to keep our minds open to both possibilities that this is a trick question (in which returning null should achieve an A pass :) ), and that butchery of generics is acceptable. It would be interesting to know whether there are additional semantics (eg javadocs or other narrative) for this method that Clemens has not told us about.

    Bruce
  • EJP
    EJP Member Posts: 32,920 Gold Crown
    I always found it surprising that the case where a return type <T> can't be inferred from the arguments is even legal. Any background on that?
  • although the type inference algorithm in the JLS is littered with Discussions, it is surprising silent (section 15.12.2.8) about using return type, and certainly nothing about this case.
This discussion has been closed.