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

Both those examples are exactly the type of thing you cannot do in Java because of type erasure. For instance, your first example would need to be:

    <T> static void addItem(List<T> list, Class<T> type) {
        T item = type.newInstance();
        list.add(item);
    }



Can't that be solved by passing these types around under the hood, but allowing the language to sugar them out when they are known? I thought this kind of half-erasure was how some languages already operated on runtimes that erase generics.


That's basically what Java does. Java class definitions contain the full, reified type information, but when the runtime loads the class, those types are lost. Only the compiler uses them.

There are some ways to introspect generic types in Java, but you need a concrete binding. For instance, if a method returns List<Integer>, you can in fact see that it returns List<Integer> and not just List. Method.getGenericReturnType() would return a ParameterizedType with a List raw type and Integer type arguments. But that requirement for it to be a concrete binding means it's not really helpful from the context of writing a generic class or method in the first place.

Using the above example, I'm not sure how you could desugar that without having the type known to the runtime. The generic method is going to be the same code no matter the type provided, but the type provided is necessary in order to know the type to construct. So either the runtime must provide the type, or it must be given as a parameter.

Additionally, glossing over the issue like that creates a huge trade-off. Now programmers must build a mental model of when the compiler can and can't do the type binding. The difficulty of building such a mental model accurately is one of the central complaints against Rust's borrow and lifetime checker(s).




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: