I ran across a piece of code that looked somthing like this on another site and it seriously blew my mind . How does the compiler infer the parameterized type of List<T> when the type is still unknown at the point of method invocation. Looks like Java voodoo to me.
[ March 15, 2006: Message edited by: Garrett Rowe ]
Some problems are so complex that you have to be highly intelligent and well informed just to be undecided about them. - Laurence J. Peter
declares T as a type (any type) that is used in List<T>.
jan
Garrett Rowe
Ranch Hand
Joined: Jan 17, 2006
Posts: 1295
posted
0
In each case in the sample methods in that tutorial, the type <T> was inferred at the time of method invocation. Here <T> is unknown until the left-hand side of the assignment operator is evaluated, after the method call returns. Just looked kinda strange to me. I had never seen it done that way before.
Originally posted by Garrett Rowe: Here <T> is unknown until the left-hand side of the assignment operator is evaluated, after the method call returns.
Yeah, that's what I thought you meant. It is strange looking! Even stranger (until you think about it) is the fact that a bare call like
FinalTest.newList()
compiles too!
But the thing is that generics work by "erasure" which means that in reality, an ArrayList<String> is identical to an ArrayList<Object>. There are annotations in the class files that help the compiler reconcile types, but ultimately, at runtime, the types are gone. So if you write a method that returns a parameterized value with a free type parameter like this, then the compiler can simply treat it as a value of the "correct" type.
The type of T is inferred by the return type. If it cannot be inferred (you can come up with examples if you like), you will receive a compile-time warning. As far as I'm aware, this is common knowledge and not "strange" - is it not covered in the generics documentation?
Originally posted by Tony Morris: If it cannot be inferred (you can come up with examples if you like), you will receive a compile-time warning.
Actually, not so much. A bare call to the generic method in which the return value is discarded will compile without warnings; obviously no type parameter was supplied here. It doesn't matter in Java, but it sure as heck would matter in C++, where the code couldn't be compiled at all.
As far as I'm aware, this is common knowledge and not "strange" - is it not covered in the generics documentation?
It is. It's just strange looking to someone new to generics but with some C++ templates experience.
Garrett Rowe
Ranch Hand
Joined: Jan 17, 2006
Posts: 1295
posted
0
If it cannot be inferred (you can come up with examples if you like), you will receive a compile-time warning.
This compiles without warning:
This however recieves a warning: I can infer from this I guess that the unsafe operation is adding an element to the raw List.
[ March 15, 2006: Message edited by: Garrett Rowe ] [ March 15, 2006: Message edited by: Garrett Rowe ]
Tony Morris
Ranch Hand
Joined: Sep 24, 2003
Posts: 1608
posted
0
The warning you receive here is unrelated to type inference based on return type. I will come up with an example when I get a chance to demonstrate what I mean - I didn't mean simply invoking the method without a return type.
Or someone might like to come up with an example themselves I recall many times when writing ContractualJ that I had to make sure an explicit invocation permitted a valid type inference.
Originally posted by Garrett Rowe: I can infer from this I guess that the unsafe operation is adding an element to the raw List.
Adding an element to any Collection where the parameterized type hasn't been declared will generate a warning. Why? Because a "List<String>" is a "List" and can be assigned to a variable of type List using widening reference conversion, which generates no warning. If the compiler allowed you to invoke generic methods on a raw List then you could add any Object to a List<String> without a warning.
I believe invoking any method that takes a parameterized type for a parameter will generate a warning if it's invoked on a raw type.