They are a big improvement over not having generics and, in my experience, one seldom sees those workarounds you mentioned. Sure, when they are necessary they are ugly... but how often are they needed in standard application code?
IMHO deserializing JSON is quite a common application code.
If you are really interrested I'd create example code, but (as being lazy, and the mentioned code not being my property) I'd hope to take my word for granted :)
edit: I wrote useless in many cases!
https://github.com/jhalterman/typetools
...but proper support of reified generics certainly would have been better.
I guess that's why the original comment said useless in many cases. Not completely useless. The next sentence also said they are way better than no generics.
Need to pass in a class type, but it's of a list?
List<YourType> list = new ArrayList<>(); yourfunc(list.getClass());
C# got all this junk right.
Java generics problems: "primitive types" cannot be used as type parameters. Type erasure makes type parameters unavailable at runtime, which sometimes causes many problems.
When you see java code passing a .class as a constructor/method parameter, that is often a workaround.
Try Stream.toArray(). Type erasure makes it a pain and forces you to provide an array Supplier.
Other Example: you cannot have overloads of a method one taking Function<T,U>, other taking Supplier<T> because their erased signatures are equivalent.
Disclaimer: I still prefer Java when C# is not an option, yet I reserve the right to criticize its shortcomings.
We use Groovy for some things, but here I'd stick to Java.
Also Groovy has limited IDE support.
Yes you can use ArrayList but you'd think that something as fundamental as an array would work with generics.
https://docs.oracle.com/javase/tutorial/java/generics/restri...
interface List<T> { T[] toArray(T[] item); }
You need to pass in a T[] because arrays keep their types at runtime but the generics don't.
Now, I've never worked with Java, but if you say that java generics make you miss C# generics, they must be really horrible :-)
With generics, you can only pass complete types as generic parameters; templates accepts types, templates and integral constants.
You can't have partial specializations with templates.
Typedef. This is the most annoying limitation I found in C#. You cannot type:
typedef vector<MyClass> MyList;
and have it valid in the whole project.Having worked extensively with both I think Swift learned a lot from C# (and many other languages).
As for Concepts... No one seems to be able to agree on them so I'm not holding my breath.
Tons of generic APIs essentially do the same thing by passing in the class object in the constructor, e.g. http://stackoverflow.com/a/1090488/1075909 . The question for people not that familiar with the Java type system is often "Why do I have to pass in the class object when I just declared the type parameter in my instance?"
That's not the only thing you need to workaround because of type erasure (the "TypeToken" stuff in a lot of deserialization libraries is another one that comes to mind frequently), but it's probably the first annoying example people hit.
The only reasonable way to do this is to accept a lambda that tells the compiler exactly what call is legal to create an instance of T.
And that's called a factory.
public static T Factory<T>() where T:new() { return new T(); }
Having a type argument available; as adevine mentions, performing type-level things rather than just instance-level things. A smarter language than Java could handle this with hidden arguments, or passing along a dispatch table for type-specific actions when constructing a generic type. Things get trickier when you're e.g. storing a reference to a static generic method.
In reality, there's a continuum between C++-style generics-as-parameterized-syntax-trees and Java's generics-as-ignorable-type-checker-façade. Going full C++ isn't what you want; the error messages on failure to instantiate are unpleasant. Going full Java leaves you with a few holes. C# is probably a small bit too far in the C++ direction - instantiations can add up, despite .NET reusing instantiations where the type arguments are object references (that is, the CLR will effectively erase types if your type arguments are reference types, but you can't observe this without escaping the type system).