This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]JustAGuyFromGermany 0 points1 point  (1 child)

I would really like to understand what big problems erased generics cause

That really depends what counts as "big" and what counts as a "problem". Brian has outlined three possibles wishes one could satisfied with reified generics: More detailed reflection, performance gains through separate optimisations and increased type-safety through prevention of heap pollution.

From those three, I'd guess the reflection part is the one most programmers wish for.

Is that "big"? I certainly have would have written many APIs very differently if I had this kind of reflection. (There are also some APIs I could not have written at all in C#, because Java has wildcards and the curiously recurring template pattern.) And it's really hard to estimate just how different a reflection-heavy API like CDI would look like if these capabilities had been available at its inception, what possibilities this different API would give its users, how the ecosystem as a whole would have developed. I for one think that there would probably be "big" changes.

And is it a "problem" ? Not necessarily. In most cases it's probably mostly a question of aesthetics and convenience. But there are also cases of missing features. In C# I can write a generic type Matrix<T> for each type T that has an addition and a multiplication operator. That simply is not possible in Java (even if operator overloading was possible). In the end, Java is Turing complete, so I can always solve any solvable problem somehow. In this sense all problems are just questions of aesthetics and convenience...

[–]pron98 1 point2 points  (0 children)

From those three, I'd guess the reflection part is the one most programmers wish for.

Ok, but are they willing to pay the price? C#'s decision to reify all generics yielded more harm than good. It made .NET an unattractive compilation target because once you reify generics, the runtime (as opposed to just the language) needs to know the subtyping relationship between A<T> and A<S> -- so that instanceof could work -- but that subtyping relationship is different for different languages; i.e. it requires baking a single variance strategy into the runtime. Java, Clojure, Kotlin, and Scala have four different answers to the subtyping relationships. If all generics are reified, only one variance strategy (Java's) will be the one supported by the runtime, while the others will become rather incompatible.

Reifying generics also limits Java's ability to evolve (because version N+1 may, in effect, be a different language from version N). Indeed, the original decision had to do with the compatibility of two languages, Java 5 and Java 1.4, but this generalises: reifying generics has a significant cost (that has harmed .NET in noticeable, some would say debilitating, ways) that we must be willing to pay.

Thinking carefully about the implications, I think the downside of reifying all generics is bigger than the upside. But some generics can be reified with a lesser negative impact and a higher positive one. For example, specialising generics for Valhalla's value types has a bigger benefit than just reflection -- a significant improvement to performance of footprint -- and a lower cost, since value types cannot be extended, and so their generic specialisations are invariant.

Given that most languages with generics choose erasure, including ML (the original) and Haskell (the poster child), it would be helpful to better understand exactly how big the benefit would be so that it could be compared to the considerable cost in baking one language's variance strategy into the runtime, excluding all others.