11 ms·
Background: how we got the generics we have (2020)
- gkorland 6y agoI think the way Rust took with Generics should be the next step for Java, it for sure can boost the Java apps performance. In Rust you have both types erasure and C++ style templates which don't erasure the types.
- dep_b 6y agoThere is no next step for Java, because of backwards compatibility this is as good as it gets.
- Felk 6y agoWhile it does need to maintain backwards compatibility, Project Valhalla seems promising on improving on some of Java Generic's pain points. So it's not a dead end quite yet
- kaba0 6y agoI don’t think templates are wanted, but with the coming of unification of primitive and reference types, Java could get a huge speedup in performance.
- henryjcee 6y agoThis has passed me by, what's happening?
- BenoitP 6y agoNot so much a unification, as the new constructs sort of enhance and retrofit current primitives types. These new primitives are "class instances that lack object identity and can be stored and passed directly, without object headers or indirections". It will allow (almost) direct control over data layout. At least make it so that it is cache/prefetch/SIMD friendly. Here is the JEP: https://openjdk.java.net/jeps/401 https://openjdk.java.net/jeps/401
- mrkeen 6y ago> the way Rust took with Generics should be the next step for Java I have a List<Integer>. Maybe I want to replace List with something else, call it L. Can I write L<Integer> in Java? No. Rust? No. C#? No Kotlin? No. Does Go have generics yet? Once it does, I'm sure it'll be a No as well. Haskell and Scala got it right.
- riffraff 6y agoI don't understand what you're saying, what is the problem with L<Integer> ?
- mrkeen 6y agoThere shouldn't be a problem with it! <L> void process(final L<Integer> input) { } ------------------------------------------ <L> void process(final L<Integer> input) { ^ required: class found: type parameter L where L is a type-variable: L extends Object declared in method <L>process(<any>)
- p2t2p 6y agoWorks perfectly: public <T extends Collection<Integer>> T process(T collectionOfInteger) { return collectionOfInteger; }
- petersellers 6y agoWhat if your "T" isn't a collection though?
- Joker_vD 6y agoThen what can you really do with it except of returning it back as-is?
- throw149102 6y ago
- kasperni 6y agoA Parametric VM [1] is part of Java's project Valhalla. However, it is currently some releases away. [1] https://cr.openjdk.java.net/~jrose/values/parametric-vm.pdf https://cr.openjdk.java.net/~jrose/values/parametric-vm.pdf
- _old_dude_ 6y agoVery cool, it seems to be the best of both worlds, the specialization of the class/fields is done the first time a specialized type is instantiated while the specialization of methods is done by the JIT. And the VM can specialize on any values, not just types.
- dep_b 6y agoI really don't enjoy anything about Java except for the JVM and if I press somebody that advocates for Java about what the reasons are that I should use Java it's always about either the JVM or the fact that there's so much of it around. But never really a solid argument why the language itself is nice to work with. If I would want to use something like Java for a project, I would always pick C# which is a better Java in all aspects.
- mrkeen 6y agoDoes C# handle generics better than Java?
- LandR 6y agoC# generics are reified.
- accountLost 6y agoYou can't easily create a instance of the generic type in java. for example : return new T(); is possible in C#, not in java.
- ohgodplsno 6y agoThere is a way-ish, which is passing a Class<T> as an additional parameter and doing clazz.newInstance(). Definitely not pleasant though.
- Felk 6y agoFor that particular use case it may be better to pass a constructor reference / new instance supplier to not rely on reflection.
- Felk 6y agoAs "better" isn't clearly defined, here are some things that some people might consider superior: - primitives or any custom value types/structs can be used. No need for boxing or method duplication for primitives. - type information available at runtime, no need to pass 'Class<T>' parameters. - type constraint 'new' available, which means it must have a default constructor so you can do 'new T()'. No need to use reflection or pass a constructor parameter. - type constraint 'notnull' available - class-scoped compiler enforced covariance and contravariance, though I think you can get similar results with java's "? extends T" and "? super T" constraints
- haolez 6y agoKind of off topic, but is something using either Lombok[0] or Manifold[1] to have better ergonomics in Java? It sounds like a brilliant idea to me, but I don't use Java on a daily basis. [0] https://projectlombok.org/ https://projectlombok.org/ [1] https://github.com/manifold-systems/manifold https://github.com/manifold-systems/manifold
- windock 6y agoLombok is very widely used in places I worked. Love it myself.
- deleted 6y ago[deleted]
- virmundi 6y agoThe problem I have with Lombok is that suddenly it’s hard to trace getters and setter from the Pojo. By this I mean asking the question, “where is getId() used” is hard if I want to use the find references feature of the IDE.
- lmilcin 6y agoI also have mixed feelings about Lombok. For example, if you want to automatically create getters and setters to all private variables, why not make them public in the first place? I hate when tools mess with IDE. What about guys using Emacs (or any other editor that does not understand Lombok)? I think generating code from IDE is fine as well as having code generated from build system distributed along with code, but having that code generated through magic of annotation processor is not as nice. I also suspect that Lombok messes my IDE on a deeper level but I have not yet a good concrete proof. Recently I am more and more frequently finding situations where Idea messes up understanding correct types of things and it takes for it some time to catch up (and sometimes reloading the file). On the other hand I love small things like creating builder or logger. Which is to say these can be just as easily generated from a template, no annotation processor needs to be involved. I think main feature of Java for many years were its IDEs which would allow to run accurate refactorings or always understand who is using particular piece of code, what is exact call hierarchy, etc. I feel loosing that is going to make Java much less useful for me when I try to analyze large project or run huge refactorings.
- datavirtue 6y agoThis is a great write-up. Accessible but thorough.
- xwolfi 6y agoOne flaw of the article, that is indeed interesting, is that it seems to ask us to accept a fact that serves little purpose. Yeah, we understand why the designers made the choice because it was the best for them, and they did think a bit of their users, but just a bit. Decades later, we're still wondering as we get to more and more complex use cases, why we're stuck with passing the class object to all our generic types just to know who we are. It's really a rare instance where Java gave an engineer's solution when they should have given us something more, like a compile flag, a fork, a GenericArrayList<Something> that would be reifed, anything, rather than excuses about ecosystem, backward compatibility perfection, etc. I understand why they took that decision, I don't understand how it helps all of us do meaningful generics :(
- ChrisArchitect 6y agoalternate url also submitted 9 months ago, I dunno https://news.ycombinator.com/item?id=23621185 https://news.ycombinator.com/item?id=23621185
- Const-me 6y ago> This would have devalued almost all the Java code in existence at the time. So, instead of doing that, they have decided to devalue Java code in long term, by deliberately making language and runtime less useful. Interesting choice.
- bassman9000 6y agoWithout this requirement, generifying a class would require a “flag day” where all clients and subclasses have to be at least recompiled, if not modified – all at once. For a core class such as ArrayList, this essentially requires all the Java code in the world to be recompiled at once (or be permanently relegated to remain on Java 1.4.) Since such a “flag day” across the entire Java ecosystem was out of the question, we needed a generic type system that allowed core platform classes (as well as popular third-party libraries) to be generified without requiring clients be aware of their generification. (Worse, it wouldn’t have been one flag day, but many, since it is not the case that all the world’s code would have been generified in a single atomic transaction.) Another way to state this requirement is: it was not considered acceptable to orphan all the code out there that could have been generified, or make developers choose between generics and retaining the investment they’ve already made in existing code. By making generification a compatible operation, the investment in that code could be retained, rather than invalidated. It's great to see such care for the users, while at the same time improving the platform to make it one of the top performing ones.
- zeroimpl 6y agoFun fact - if you don’t like Java erasing types by default, you can just pass them along manually yourself. There’s a bunch of ways to do this, but I’ll just leave this one trick here. Instead of: List<Integer> x = new ArrayList<Integer>(); write this: List<Integer> x = new ArrayList<Integer>(){}; Now you’ll be able to ask at runtime and determine it is a subclass of List<Integer>.