While studying generics, I noticed a difference in type introduction syntax between generic methods and generic types (class or interface) that confused me.
The syntax for a generic method is
<T> void doStuff(T t) { // Do stuff with T }
The docs say
The syntax for a generic method includes a type parameter, inside angle brackets, and appears before the method's return type
The syntax for a generic type is
class Stuff<T> { // Do stuff with T T t; }
The docs say
The type parameter section, delimited by angle brackets (<>), follows the class name. It specifies the type parameters
For neither it states why it must come before or after.
In order to be consistent with each other, I expected either the method syntax to bevoid doStuff<T>(T t) {}
or the type syntax (for class) to be class <T>Stuff {}
, but that is obviously not the case.
Why does the one have to be introduced before, and the other after?
I have used generics mostly in the form of List<String>
and argued that <String>List
might look weird, but that is a subjective argument, besides for methods it is like that as well. You can call doStuff
like this.<String>doStuff("a string");
Looking for a technical explanation I thought perhaps <T>
must be introduced to a method before specifying the return type because T
might be the return type and the compiler maybe isn't able to look ahead like that, but that sounded odd because compilers are smart.
I figure there is an explanation for this beyond "the language designers just made it that way", but I could not find it.
From the point of view of reflection, the difference between a generic type and an ordinary type is that a generic type has associated with it a set of type parameters (if it is a generic type definition) or type arguments (if it is a constructed type). A generic method differs from an ordinary method in the same way.
Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.
Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.
A Generic class simply means that the items or functions in that class can be generalized with the parameter(example T) to specify that we can add any type as a parameter in place of T like Integer, Character, String, Double or any other user-defined type.
The answer indeed lies in the GJ Specification, which has already been linked, quote from the document, p.14:
The convention of passing parameters before the method name is made necessary by parsing constraints: with the more conventional “type parameters after method name” convention the expression
f (a<b,c>(d))
would have two possible parses.
f(a<b,c>(d))
can parsed as either of f(a < b, c > d)
(two booleans from comparisons passed to f) or f(a<B, C>(d))
(call of a with type arguments B and C and value argument d passed to f). I think this might also be why Scala
chose to use []
instead of <>
for generics.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With