Still way better than no generics at all, but if you are used to better implementations these random limitations can be really painful..
Still way better than no generics at all, but if you are used to better implementations these random limitations can be really painful..
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.
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).
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.
- Reification
- Declaration-site generics
- Default covariance when variance not specified
- Variance inference!
In practice default covariance is usually the most suitable; it's the pragmatic approach. But you can make a generic type super sound, if that's what you need. And with variance inference your generic type can safely inherit from generic Java types.http://gosu-lang.github.io/2015/11/22/threading-the-needle.h...
So, claiming type erasure making generic useless is a false argument.
void func(List<ClassA> list);
void func(List<ClassB> list);
Using type erasure, I cannot specify functions that are overloaded based on the generic type of an argument. To the runtime, both of these accept an argument of type List<Object>, and so it is ambiguous which one to call.In C++, which does not use type erasure, this sort of function overloading works as expected.
Sure, I could use Integer/etc, but now each stage of my transform is creating a ton of garbage and I no longer get data locality.
One such thing missing from .NET for example are higher-kinded types. Basically people end up with the need for `instanceOf` because they aren't able to write generic code that abstracts over containers such as List[T].
And this holds back language development on top of .NET actually. There are good reasons for why alternative languages flourished on top of the JVM and not on top of .NET, in spite of its original marketing, which is a little ironic. Not the only reason mind you, other reasons where availability on Linux, having an easier time to generate bytecode along with debugging symbols, more mature tooling, etc, but having reified generics in the runtime either means that you have to limit your language (e.g. C#'s type-system with a different syntax), or it means that you have to do the type erasure yourself and always have performance problems and be considered a second class citizen. Lack of higher-kinded types is actually what's holding F# back as an FP language, because in FP there is a lot of opportunity to abstract over M[T] types, that are just not doable in a static language without HKT.
And don't get me wrong, I like dynamic typing as well, but the problem with languages like Java and C# are that they are neither here, nor there, in many ways being the worst of both worlds.
And the only advantage that .NET's reified generics have over Java is actually the specialization it is doing for primitives. Which is nice for performance reasons, since you avoid boxing and so on, but doing specialization doesn't necessarily need to be a runtime feature, when it can very well be a feature of the language's compiler. And we weren't talking about performance anyway.
Admittedly this is a little annoying, possibly even "really painful" so this doesn't really contradict your view... I don't find it really painful, just a little annoying, but that could be because I haven't used C# or another language people say has better generics so I don't know what I'm missing...
http://stackoverflow.com/questions/20918650/what-are-the-ben...
If anything, my opinion is that the abundance of so many dynamic languages on the JVM, and the active use of those dynamic languages in JVM projects, has much more to do with how no one really wants to work in Java than anything to do with how generics work (or don't work) in the JVM.