News for hackers. Stuff that matters.
Re:Modern programming languages require generics by formerly_proven on Tuesday May 24, 2022 @10:58AM (#31492975)
> Java is the only one on this list that has a different approach. Instead of using generics at compile time, it is actually doing a dispatch of the code to optimized routines based on runtime types. That does mean that they had to write the same sort code multiple times, of course.

> Using Java:

    public static void sort(int [] a);
    public static void sort(long[] a);
    public static void sort(Object[] a);
Perhaps they meant it another way, but this makes it sound like there is runtime dispatch between these different signatures - there isn't. int, long etc. are unboxed types in Java, which are not Objects, and cannot be used for Object-based generic type-erasure. So the decision which of these sorts is going to be used is made by the compiler. All Objects are sorted using the third signature.
Re:Modern programming languages require generics by mrighele on Tuesday May 24, 2022 @05:31PM (#31497764)
Java generics works only on reference types (i.e. anything that derives from Object), and not on primitive types like int and long. For this reason, if you want a method that work on both primitives and reference types, you have to provide distinct implementations. This is true even if you provide a generic version like

    public static <A> void sort(A[] e);
You will not be able to use the above method with an int[]. Whenever possible the compiler will try to be helpful, and automatically box/unbox primitives for you, so for example the following will work

    public <A> A max(A a1, A a2);

    /* ... */
    void foo() {
        int x = max(1,2);
    }
this comes at the cost of boxing ints inside Integer, though.

So, if you ignore for a moment primitives types, whenever you have generics, everything boils down to a single method accepting Objects and returning Objects. What the JVM does is to do runtime profiling of what actually you are passing to the generic method, and generate optimized routines for the "best case". In theory this is the best of the two worlds, because (unlike, let's say, C++) you will have a single implementation of the method, avoiding code explosion, but if you use it in an hot spot you get the optimized code.

In a way, it is quite wasteful, because you throw away a lot of information at compile time, just to get it back (and maybe not all of it) at runtime through profiling, but in practice it works quite well.

A side effect of this is this makes the JVM a wonderful VM for running dynamic languages like Ruby and Python, because that information is _not_ there at compile time. In particular GraalVM/Truffle and exposes this functionality to dynamic language implementations, allowing very good performance (according to their website [1][2], Ruby and Python on Truffle are about 8x faster than the official implementation, and JS in line with V8)

[1] https://www.graalvm.org/ruby/ [2] https://www.graalvm.org/python/

Re:Modern programming languages require generics by amenghra on Tuesday May 24, 2022 @05:47PM (#31497880)
The state of Java’s type erasure makes me quite sad when I need the type information via introspection.

I’d say the best situation would be keep the type information at compile time but let the VM decide if multiple implementations are needed or not at runtime.

Re:Modern programming languages require generics by admax88qqq on Tuesday May 24, 2022 @06:22PM (#31498213)
What information do you need that's gone? Type erasure happens but the objects still carry their true dynamic type with them, isn't that sufficient?
Re:Modern programming languages require generics by cstrahan on Tuesday May 24, 2022 @07:29PM (#31498770)
The arguments still carry their dynamic type, but you lose the type parameters for the functions applied to those arguments. Of course, at the call sites for known working code you can infer the type parameters -- let's say for example that the function has one type parameter and one argument of that same type: use reflection to get the of that argument and, under the premise that you're code doesn't have a runtime type error, you know the type param for that function is the very same.

However, what if you have a collection of generic functions divorced from the arguments? There's no way from the function alone to determine the type params. So you can't write code that reflects over a collection of generic functions and dispatches solely on the type params.

And, while I've been speaking of functions, this really generalizes to any generic type. If you have e.g. a collection of PetTrainer<?>, and you have a code path in which you have a pet of type Dog or Cat, how can you use only reflection to choose a trainer upon which you can call Train(pet)? You can't.

(I don't Java, so please give me a little slack wrt syntax.)

Re:Modern programming languages require generics by admax88qqq on Tuesday May 24, 2022 @08:03PM (#31499024)
Sounds like a missed opportunity for polymorphism. The whole point of OO and polymorphism is to do let the dynamic dispatch call the right method body for you.

Implementing that by hand using reflection just sounds plain wrong.

Would love to hear of a concrete real world example where this was an issue

Re:Modern programming languages require generics by anonymoushn on Wednesday May 25, 2022 @12:26AM (#31500595)
Java users have to use double dispatch and such, because Java only implements dynamic dispatch on the type-erased type of the first function argument.

The last bit of the GP comment is an example of the sort of thing that isn't possible with generics in Java, because the PetTrainer-of-Dogs and PetTrainer-of-Cats are indistinguishable at runtime. If you want to solve the problem with dynamic dispatch on the type-erased type of the first argument only, you could *stop using generics*, write a separate class for each generic instantiation you would have had, send every pet to every trainer, and have each trainer check the runtime type of their argument and do nothing if it's the wrong type. This probably isn't what anyone really wants to write or an acceptably cheap thing to do at runtime.

Nobody actually deals with PetTrainers but people do deal with MessageSubscribers that work more or less exactly as described, and the type system does nothing to help. For a concrete example of the horrors of double dispatch, you could see the wonderful book Crafting Interpreters.

Re:Modern programming languages require generics by throw868788 on Wednesday May 25, 2022 @01:49AM (#31501041)
This is what I think .NET's generics are like. Type information including all parameters are available, and JIT does as you say. The approach has some advantages (binary size, less memory instantiations when required) but a slight cost when method is first JIT'ed. This only works for VM languages though.
Re:Modern programming languages require generics by taeric on Tuesday May 24, 2022 @11:15AM (#31493199)
Yeah, this really needs to point out that the elements in Arrays.sort have to be Comparable. More, they have to be Comparable with each other. Should probably show the Collections.sort that takes a Comparator to really make the point that that is dispatched at runtime.

But then you would probably need to cover just how aggressive the JIT is in the JVM and how the costs may not be what you would think they are.

Re:Modern programming languages require generics by GordonS on Tuesday May 24, 2022 @02:26PM (#31495765)
You're not wrong, but I feel like this doesn't need explicitly spelled out, as it would be obvious to any Java dev (or C#, or indeed probably any language with generics).
Re:Modern programming languages require generics by taeric on Tuesday May 24, 2022 @02:31PM (#31495833)
I think my problem is that there is no runtime dispatch between the methods that were listed. Such that that was a bit of a non-sequitur for the point at hand.
Re:Modern programming languages require generics by Koshkin on Tuesday May 24, 2022 @12:32PM (#31494225)
This has little (nothing?) to do with generics, though. This is an example of function (name) overloading.
Re:Modern programming languages require generics by tialaramex on Tuesday May 24, 2022 @03:13PM (#31496332)
The technical term for this feature in this context is "ad hoc polymorphism". It's polymorphic because it only allows you to specify different types, you can't just go around making six different foo() methods that all take a string - that doesn't work because the compiler can't tell which one you wanted, and it's ad hoc because you can just fill out whatever you want in each version.

The negative consequence of being ad hoc is that there's not even a very strong implication beyond the name that these different functions all do the same thing, and sure enough they often don't. So now either your users must read your documentation very carefully, or sometimes they will have unhappy accidents. This is made worse in many modern languages with type inference where your users may be mistaken about which of the functions they're actually calling since they don't always know the type of anything anyway...

Ad hoc polymorphism is over-used because it is relatively cheap to implement, and it's cheap to add more of these overrides later.

Re:Modern programming languages require generics by Koshkin on Tuesday May 24, 2022 @03:47PM (#31496726)
Well, having methods in different classes that happen to share the same name is also an example of that, and so it cannot be avoided (not in practice, anyway).
Re:Modern programming languages require generics by zwieback on Tuesday May 24, 2022 @11:04AM (#31493051)
Yes, seems like Java generics are an argument against the "generics allow optimization" argument. Maybe I misunderstood what he was trying to say.
Re:Modern programming languages require generics by kaba0 on Tuesday May 24, 2022 @01:11PM (#31494811)
That is also not true — Java’s generics don’t add any overhead. If you would have written an ArrayList implementation before generics you would have had the exact same compiled method signature like put(Object o) and Object get() - the only difference is that it would not have been type safe, that is you could have inserted a String into it while you might have expected to get an Integer on the other side.

So generics are completely a language semantic concept in case of Java, with no performance detriment/benefit. Of course more information can be used up for better optimizations as well, see Rust’s or C++’s generics/templates.

Re:Modern programming languages require generics by titzer on Tuesday May 24, 2022 @04:16PM (#31497062)
The javac source compiler erases source-level types and inserts casts into the bytecode (at usage sites, not within the generic class). So if you have ArrayList<T>, it will generate one version of ArrayList. But usage sites will have casts inserted where necessary. In particular, in a use of put() on the outside doesn't need a cast (because the single implementation of ArrayList uses Object underneath), but get() will have a cast from Object to String at the call site.
Re:Modern programming languages require generics by marginalia_nu on Tuesday May 24, 2022 @11:08AM (#31493109)
The path Java chooses for optimization is through JIT, but that's entirely orthogonal to generics. Java generics are a syntactic construction, there really is no JVM support for them what so ever.
Re:Modern programming languages require generics by cogman10 on Tuesday May 24, 2022 @12:52PM (#31494521)
It's complicated. There actually IS JVM support for generics in surprising locations. Just not at method dispatch... sort of.

For example

    void <T extends Foo> bar(T f);
will, under the covers, create a function that looks like

    void bar(Foo f);
If you create a class

    class Foo implements Supplier<Bar> {
        Bar get() { return new Bar(); }
    }
The method signature for `Foo` does in fact return a `Bar` type and not some `Object` type even though `Supplier<Bar>` would imply that is erased. The same applies to if that generic was used within the method parameters.

That generic type information is, in fact, stored off at the class level and can be extracted through Java's reflection API.

This is how magic like

    json.parse("[1,2,3]", new TypeReference<List<Integer>>{});
is getting it's stuff done. It's creating a new anonymous class of "TypeReference<List<Integer>>" which the json library can then use to introspect and pull the generic information out and know that it should create a `List` of `Integer` rather than of `Long` or `Double` or a `Set`.

This makes generics more than just a syntactic construction in Java.

Re:Modern programming languages require generics by bumper_crop on Tuesday May 24, 2022 @02:14PM (#31495592)
The JVM still doesn't know about generics. The explanation you provided is entirely at the compiler (javac) level, and the JVM is still oblivious to it. There is no special dispatch, or optimization. At best, you could say there is support in the Java standard library, but not in the JVM or hotspot or anything from running "java".

An easy way to verify: Are generics in Clojure, Scala, or JRuby the same as Java (the programming language)?

Re:Modern programming languages require generics by marginalia_nu on Tuesday May 24, 2022 @01:03PM (#31494692)

    class Foo implements Supplier<Bar> {
        Bar get() { return new Bar(); }
    }
Bar isn't a generic in Foo though (if we remove the implements-clause, that is very clear). It's only a generic in Supplier, so I don't see where the implied erasure quite comes from.
Re:Modern programming languages require generics by cogman10 on Tuesday May 24, 2022 @01:10PM (#31494786)
I didn't add it, but the `get` method comes is an override from the `Supplier`.

For example, if we did something like

    class Foo extends HashMap<Foo, Bar> {
      @Override
      Bar put(Foo f, Bar b) {
        super.put(f, b);
      }
    }
The `Map` signature for `put` is `Object put(Object, Object)` due to erasures. However, because you are extending and specifying the generics, the overriden method ends up reifying the type.

All this is to say that generics end up being a little more than just syntactic sugar.

Re:Modern programming languages require generics by marginalia_nu on Tuesday May 24, 2022 @01:20PM (#31494920)
If you consider this example:

    class Base<T> {
        T f() { return null; }
    }
    class A<T2> extends Base<T2> {
        @Override
        T2 f() { return null; }
    }
    class B extends Base<Integer> {
        @Override
        Integer f() { return null; }
    }
    class C {
        Integer f() { return null; }
    }
Base has a parameter T which is erased in Base.

A has a parameter T2 which is erased in A.

B because B is not a generic class and nothing is erased from B.

Base has the same shape as A; B has the same shape as C.

Re:Modern programming languages require generics by mrighele on Tuesday May 24, 2022 @04:58PM (#31497476)
The example you provide has little to do with generics, but how inheritance works.

In particular if you override a method in a derived class, you're allowed to return an instance of a more specific class (in your example, Bar is an Object so it is fine). At runtime, your example is equivalent to something like

    interface Supplier {
        Object get();
    }

    class Foo extends Supplier {
        Bar get() { return new Bar(); }
    }
Re:Modern programming languages require generics by dcminter on Tuesday May 24, 2022 @12:58PM (#31494606)
For most purposes, but there's a little in reflection and so forth. For example:

https://docs.oracle.com/en/java/javase/17/docs/api/java.base...()

Edit: sibling comment by cogman makes the case more thoroughly.

Edit: also HN mangles the link to Class.getTypeParameters()

Re:Modern programming languages require generics by Smaug123 on Tuesday May 24, 2022 @06:02PM (#31498003)
Re:Modern programming languages require generics by mumblemumble on Tuesday May 24, 2022 @11:35AM (#31493468)
I think the author got it slightly wrong here because he's conflating the programming language feature and its semantics with the run-time implications of the technique(s) you use to implement that feature.

For what it's worth, this seems to be a common misunderstanding where generics are concerned.

Re:Modern programming languages require generics by lifthrasiir on Tuesday May 24, 2022 @11:08AM (#31493108)
Generics allow optimization, but that optimization has to be implemented in the first place. Java generics is an afterthought so you can expect such a suboptimal design.
Re:Modern programming languages require generics by kaba0 on Tuesday May 24, 2022 @01:19PM (#31494916)
I don’t think it is fair to call it an afterthought. I would even say that it was extremely well thought out, managing to move a whole ecosystem with millions of lines of code from unsafe raw usage to type-safe generics without much hiccup, at a time when this feature wasn’t all that well known by the average developer.
Re:Modern programming languages require generics by titzer on Tuesday May 24, 2022 @04:40PM (#31497320)
Erasure was a bad design choice. C# did the exact same upgrade (add generics to the language), but they chose to reify them and add them to the binary format, with a better overall result (IMHO). C# does not have platform reach that Java has, but there are a lot of factors at play there that go beyond language design choices.
Re:Modern programming languages require generics by kaba0 on Tuesday May 24, 2022 @05:59PM (#31497981)
As I learned from another commenter here, C# 1.0 didn’t actually have generics at a language level, but was already designed that way on a vm level. So C# 2.0 could take advantage of that, making it much more of a planned feature from the start.

Also, I don’t see erased generics all that big of a deal — if there was no reflection (which is not that common feature in languages) one could not even differentiate between the two models. Haskell also does complete type erasure for example.

As for another view point, it is often brought up on HN that what made the JVM language ecosystem so thriving is exactly the type erasure model. C# effectively forces their idea of generics onto the whole platform, while JVM languages are free to choose their own model. I don’t know how true is that, but empirically it does seem to sound true (F# does share its generics model with C#, and the CLR has a history of getting some attempts at being a target which is later dropped. Though I assume it is more often due to it simply being a smaller target)

Re:Modern programming languages require generics by titzer on Tuesday May 24, 2022 @10:15PM (#31499897)
> if there was no reflection (which is not that common feature in languages) one could not even differentiate between the two models. Haskell also does complete type erasure for example.

You can, even without reflection, because the Java generic type system doesn't have the parametricity property; you can detect runtime types with cast/instanceof. Haskell doesn't have non-parametric operations, so erasure is not observable.

Re:Modern programming languages require generics by cogman10 on Tuesday May 24, 2022 @12:57PM (#31494602)
Java optimizes at the method level and the majority of methods when writing an app will have constant types used against them.

Your method signature may look like

    void foo(Iterable<Bar> b)
which would make you think of vtables and casting performance losses.

However, Java's JIT is fairly cleaver. It can tell that you always call `foo` with an `ArrayList` and it can tell that `ArrayList`'s iterator always emits a `Bar` Object. From there it can elate a lot of the type tables and virtual dispatch to just be direct dispatch. It does that at the cost of a couple of added runtime checks to make sure those assumption's aren't violated.

The impact of generics on performance has, for me, generally been pretty low. I've seen a much higher impact due to java's memory model (which is getting fixed with Valhalla).

This, btw, is how JavaScript's and indeed most high speed JITs function.

Re:Modern programming languages require generics by lifthrasiir on Tuesday May 24, 2022 @01:09PM (#31494778)
Yeah, JIT does subsume naive AOT + generics for many cases, but it is a bit unfair comparison because there is no reason for other languages to implement such optimizations (PGO is one of them). And such an inference is not free and causes usual JIT pain points.
Re:Modern programming languages require generics by malfist on Tuesday May 24, 2022 @12:49PM (#31494488)
Features added after launch doesn't make something an afterthought. Java generics are a key part of the language.
Re:Modern programming languages require generics by switchbak on Tuesday May 24, 2022 @01:03PM (#31494707)
Generics were only added in Java 1.5, they were absolutely not part of the original design, and type erasure is very much a considerable restriction in some cases. I would wager that a greenfield design would look quite different.

Whether you call that an afterthought? I'm sure the designers had this in mind, but at the same time they painted themselves into a corner somewhat with earlier decisions and a huge dedication to backward compatibility. Their work on threads on the other hand shows some real forethought and they were able to avoid most of the pitfalls that a few other language impl's fell into.

Re:Modern programming languages require generics by wvenable on Tuesday May 24, 2022 @03:08PM (#31496262)
Generics in C# were also added after launch but have a significantly better implementation. While they are a key part of the language they aren't a key part of the platform.
Re:Modern programming languages require generics by charcircuit on Tuesday May 24, 2022 @03:52PM (#31496780)
>All Objects are sorted using the third signature.

Just to be pedantic int[] and long[] are both objects, but will be sorted using the first two signatures because the JVM uses different instructions for loading and storing elements from an array. Technically you could make a single function to return an array's length since it uses the same instruction.

Re:Modern programming languages require generics by anonymoushn on Wednesday May 25, 2022 @12:41AM (#31500679)
This surely meant "All arrays of Objects"
Re:Modern programming languages require generics by dcminter on Tuesday May 24, 2022 @11:06AM (#31493073)
Plus I don't know about you, but I don't sort (or really use) arrays in Java very much. I see a lot more of the Collections.sort() methods, particularly the comparator based one.
Re:Modern programming languages require generics by layer8 on Tuesday May 24, 2022 @12:03PM (#31493814)
Collections.sort() just copies the list into an array, sorts the array, and copies the sorted elements back into the list. So it also just sorts an array under the hood. To eliminate the temporary array (at least for ArrayList), the List#sort() method was added in Java 8.

Arrays are usually still preferred over collections in the case of primitive types (int[] etc.).

Re:Modern programming languages require generics by marginalia_nu on Tuesday May 24, 2022 @11:17AM (#31493225)
Sorting arrays of primitives ought to be nearly as frequent as the need for sorted arrays of primitives due to the downright comical overhead of List<Integer>, but sorting arrays of objects has be rare in Java code written this millennium.
Re:Modern programming languages require generics by dcminter on Tuesday May 24, 2022 @12:07PM (#31493873)
I mean I don't sort List<Integer> more than once in a blue moon either. I'm much more likely to either be sorting a list of model objects with a comparator, or manipulating a collection of objects that's already been sorted by some external source.

In the unlikely event that I'm modeling something that can be represented as a list of integers AND it's a significant performance bottleneck then, sure, I'll consider the array methods. But I don't recall the need arising in the last year or two.

Enterprise Java stuff just isn't often bottlenecked on that sort of thing. Network latency fills far more of my dreams ;)

Re:Modern programming languages require generics by marginalia_nu on Tuesday May 24, 2022 @12:31PM (#31494218)
Maybe we're seeing different sides of the language then. I'm doing a lot of integer-list sorting, building a search engine in java. I'm evenly split between Arrays.sort or GNU Trove's specialized primitive collections.

The overhead of List<Integer> really can not be overstated, it can approach order 1000% memory consumption, speed is prima facie about half for dealing with collections, but in practice it can be much lower from the GC churn. Even for lists as small as a million entries this can be quite untenable.

Re:Modern programming languages require generics by Scarbutt on Tuesday May 24, 2022 @01:05PM (#31494737)
Maybe we're seeing different sides of the language then.

You are not seeing different sides of the language but participating in different domains, application/business logic programming vs more system level stuff.