Hacker News new | past | comments | ask | show | jobs | submit login

Don't know why this is being downvoted. I've been on a Java project for the last ~6 months after ~8 years of doing C#/.NET development. My brain hurts from seeing all the stupid workarounds in Java because it doesn't have real generics.



I guess it's one thing to claim Java generics have problems and another to claim they are "useless".

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?


Last week wanted to use GSON in a generic method to deserialize to a type which is generic type parameter, in a method of the abstract base class. Unfortunately it could not be done without the implementations passing up their .class via super constructor.

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!


There are ways to resolve generics declared on base classes:

https://github.com/jhalterman/typetools

...but proper support of reified generics certainly would have been better.


> I guess it's one thing to claim Java generics have problems and another to claim they are "useless".

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.


YES! to both parents here. Type erasure is a bitch.

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.


You can now use lambdas as generic type references http://benjiweber.co.uk/blog/2015/08/04/lambda-type-referenc...


What are the issues? I've never worked with Java enough to see them. I will say that reflection with generic types and methods in C# is a hassle.


In C# you can often avoid reflection using dynamic.

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.


Or even better, you can't use an array of generic types, which is just madness. Why even have a generic system if it's so half-baked.

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...


I'm not sure if you articulated your overload beef correctly. What you wrote is trivially possible so charitably, you wrote it wrong.


Could you not use Groovy for this? Using Groovy isn't harder than using another third-party library.


Yeah, if I wouldn't care for type safety, and I'd want to write validation code for stuff currently handled by GSON instead of me, by the class definitions.

We use Groovy for some things, but here I'd stick to Java.

Also Groovy has limited IDE support.


Apache Groovy's dynamic typing, closures, and shorthand collection syntax (from v. 1.0) are great for testing and playing with Java classes, and I'm told Groovy's Ruby-like MOP is useful for Grails developers, but the stuff added later (like generics in v. 1.5) made the language klunky and overdone. Best switch to Java (or Scala/Kotlin/etc) once you need anything to be typed, let alone with generics.


The most common annoyance is along these lines:

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.


I worked several years with C++ and when starting C# I was astonished how much useful stuff C# generics are missing w.r.t C++ templates.

Now, I've never worked with Java, but if you say that java generics make you miss C# generics, they must be really horrible :-)


Out of curiosity, what would you say is missing? My one big beef with templates is lack of constraints and somewhat ugly syntax, but hopefully concepts will remedy the former.


My one big beef with generics is that they only work through constraints! With templates, the compiler checks the validity of a template only when applying it to a concrete type; a generic, OTOH, needs to be valid as an independent entity. And this means that you are stuck with the limitations of the constraints: you cannot specify that your type has a constructor accepting parameters, you cannot specify static methods, nor operators.

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.


That's not inherent to generics - see Swift, which absolutely allows protocols to require static/class members or initializers. Swift 3 also adds generic type aliases (typedefs).

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.


What exactly is missing, or better in C#? I'm surprised because I've been programming in OCaml for a long time, and never missed "real" (i.e. non-erased) generics.


Unboxed values; this primarily affects performance, particularly memory performance, but with a sufficiently smart compiler could be worked around. It's unlikely any very clever JVM optimizations would see wins here though, as the assumption that everything is boxed is idiomatic.

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).


For me, it's mainly that you know the runtime type of the type parameter, so you can do things like new T() in your generic class.


Pass a factory `createT()` instead, problem solved.


Exactly - except it's gross and results in a lot of annoying boilerplate code for what should be considered a simple operation.

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.


Erasure is not the problem here, you need to be able to specify a type constraint that will allow you to invoke T(). What if T is an interface? An abstract class? A class with no default constructor?

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.


Yes, good point. But if you did have a type constraint, like C#, you would still need the runtime type info to know what to create. This is legal in C#:

public static T Factory<T>() where T:new() { return new T(); }


I downvoted it because it is not relevant to the submitted article. I would rather see discussion on the actual result - Java generics are not decidable. A discussion on whether or not Java generics are good is, in comparison, boring.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: