[HN Gopher] Background: how we got the generics we have (2020)
___________________________________________________________________
Background: how we got the generics we have (2020)
Author : kasperni
Score : 55 points
Date : 2021-04-01 09:23 UTC (13 hours ago)
(HTM) web link (cr.openjdk.java.net)
(TXT) w3m dump (cr.openjdk.java.net)
| haolez wrote:
| Kind 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/ [1] https://github.com/manifold-
| systems/manifold
| virmundi wrote:
| The 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.
| v-erne wrote:
| I'm not sure how this works in other IDEs, but lombock
| Eclipse plugin kinda solves this problem. You can run
| CTRL+Shift+G (Find references) on getter/setter that is shown
| in class outline and it will immediately give You
| getter/setter uses.
|
| https://stackoverflow.com/questions/42644923/eclipse-with-
| lo...
| LgWoodenBadger wrote:
| Depends on your IDE. IntelliJ IDEA supports this with the
| Lombok plugin
| lmilcin wrote:
| I 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.
| p2t2p wrote:
| > why not make them public in the first place?
|
| Because in future I may want to add some validation there,
| or processing, like sending events on set of a value, etc.
|
| Properties in C# was a genius move that solves it
| correctly.
| watwut wrote:
| Unless we are talking about API, then you add getter and
| setter. You might even be able to refactor all callers
| automatically via IDE. I mean, I dont mind getters and
| setters in java, it is standard at this point.
|
| But origin of it is in EJB specification, it is not
| something that would be interently needed elsewhere. It
| just "feels wrong" to programmers (including me) at this
| point.
| lmilcin wrote:
| That, in my observation, almost never happens.
| p2t2p wrote:
| I'm working in a product that is about 10 years old and 4
| months ago it went through a quite a big project which
| purpose was to add extended auditing to be more
| enterprise friendly. The system was flooded with auditing
| events on various changes into internal data. The system
| provides a public API and allows to install plugins. If
| we had to change our entities that would be a
| compatibility nightmare for thousands of plugin vendors.
| goostavos wrote:
| >why not make them public in the first place?
|
| If you're in an old school "OOP" style java codebase, where
| each class is its own little island of encapsulated state
| and behavior, the coupling of the two means that strictly
| controlling access via getters is usually required.
|
| Even in more "modern" java, where you do most of your
| programing against plain data, having Lombok attach getters
| still gives you some quality of Life benefits because you
| can use method reference rather than anonymous functions
| for high-order access (e.g. `things.map(MyClass::getName)`
| rather than `things.map(myclass -> myclass.name)`)
|
| I'm with you on mixed Lombok feelings, though. It's great
| right up until its not. It fails or doesn't work in really
| unexpected or weird ways, and is the source endless pain
| when you've got other annotation based things (like dagger)
| which then imposes annotation processing order failures.
| lmilcin wrote:
| > If you're in an old school "OOP" style java codebase,
| where each class is its own little island of encapsulated
| state and behavior, the coupling of the two means that
| strictly controlling access via getters is usually
| required.
|
| That I agree. My comment was meant to be cheeky a little
| bit as it is actually pretty difficult to find trully OOP
| application, at least in area of backend apps I am
| working in.
|
| Obviously, in OOP you are not supposed to expose your
| internal state but rather accept messages to run
| behaviour.
|
| If you are working on a truly OOP application then Lombok
| is useless. Your public class interface is all that
| matters then and you would spend more time fighting
| Lombok than just writing it manually.
|
| Lombok is only good at automating boilerplate which, if
| you have a lot of, is a sign of some other problem.
|
| > It's great right up until its not. It fails or doesn't
| work in really unexpected or weird ways
|
| That is exactly the point. Magic is fun until you find
| out that it leaks horribly and causes unintended side
| effects with all sorts of stuff.
|
| What's the point of replacing simple problem (just really
| use templating mechanism you have in your IDE) with
| complex problem (dealing with magic failing on you).
| windock wrote:
| Lombok is very widely used in places I worked. Love it myself.
| [deleted]
| watwut wrote:
| We use it, but I don't like it. I does superficial stuff for
| me, but also makes navigating and reading code harder. It takes
| somewhat more time to figure out all setter callers and stuff
| like that.
|
| It is one of those things that does not much useful, but takes
| away only little bit so there is no reason to fight it too
| much.
| dehrmann wrote:
| At least with Lombok, I've found it makes builds and tooling
| flaky, so I'd rather write an extra line here and there (or use
| Kotlin).
| setheron wrote:
| Never heard of manifold. Thanks for sharing.
| gkorland wrote:
| I 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.
| mrkeen wrote:
| > 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 wrote:
| I don't understand what you're saying, what is the problem
| with L<Integer> ?
| Taig wrote:
| The feature that mrkeen is describing is called higher
| kinded types (HKT). I.e. in Scala (and similarly in
| Haskell), you could write something like:
| def process[L[_]](input: L[Int]): Unit = ???
|
| Where `L[_]` could be any type that has a type parameter,
| e.g. `List[_]`, `Option[_]`, `Future[_]` or `Either[String,
| *]`. This opens the door to a new level of abstraction
| where other languages must resort to code generation or
| similar ad hoc-like solutions.
| [deleted]
| mrkeen wrote:
| There 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 wrote:
| Works perfectly:
|
| public <T extends Collection<Integer>> T process(T
| collectionOfInteger) { return collectionOfInteger; }
| petersellers wrote:
| What if your "T" isn't a collection though?
| Joker_vD wrote:
| Then what can you really do with it except of returning
| it back as-is?
| willtim wrote:
| This uses subtyping polymorphism not higher-kinded
| parametric polymorphism. If subtyping worked perfectly in
| all important cases, "generics" (parametric polymorphism)
| would not have been retrofitted to Java.
| fooker wrote:
| Can do with C++ though. https://en.cppreference.com/w/cpp/lan
| guage/template_paramete...
| josefx wrote:
| What operations can you perform on an L<Integer>? Does it
| work based on duck typing instead of explicitly declaring
| what base interface (Collection<Integer>) it requires?
| dboreham wrote:
| It's a similar idea to inheriting from a base collection
| class (iterable, etc). Not quite the same though. It is a
| kind of duck typing I suppose. You get to specify the
| nature of a class of types. e.g. it can be ordered, behaves
| like a number, etc.
| thinkharderdev wrote:
| Generally you are using a typeclass to specify behavior
| (which I guess is a kind of duck-typing).
|
| For example, there is a typeclass Foldable[F[_]] which
| provides the ability to "fold" (i.e. recurse over) some
| type F[_] which takes a type parameter. Then you have
| typeclass definitions for Foldable[Set], Foldable[List],
| Foldable[Tree], Foldable[Option], etc.
|
| Then if you have an operation and you want it to work on
| any collection that can be folded, then you can just define
| it in terms of a generic type that has a Foldable
| typeclass. For instance to generically sum a collection of
| ints, you might do
|
| def sum[F[_] : Foldable](ints: F[Int]): Int = ...
|
| Now you can call sum(List(1,2,3)), sum(Set(1,2,3)),
| sum(Option(1)), etc...
| Joker_vD wrote:
| Typeclass instance = Adaptor/Decorator in OOP terms,
| automatically derived (and wrapped in) for you by the
| compiler.
|
| You want to fold over Options? Make a FoldableOption
| class implementing Foldable<Option> and pass "new
| FoldableOption(myOptionValue)" to whatever places you
| need. Haskell does pretty much the same (unless they
| moved away from dictionary passing).
| p2t2p wrote:
| No worries in Java (and I bet in C#) in works no problemo:
|
| public <T extends Collection<Integer>> T process(T
| collectionOfInteger) { return collectionOfInteger; }
|
| And basically your T will be as wide as the interface/class
| it extends in the generic parameter.
|
| I guess the most Java way to do that would be using Iterable:
|
| public <Z, T extends Iterable<Z>> T process(T iterable) {
| return iterable; }
| vimax wrote:
| I want to do something like this:
|
| public <Z, T extends Iterable<Z>, R> T<R> process(T,
| Function<Z,R>)
|
| change the type parameter of T<Z> to T<R> and return an
| instance of T<R>, but the best I can do is return an
| instance of Iterable<R> because I cannot define T to have a
| type parameter.
| mrkeen wrote:
| This comment explains my problem much better than I did.
| p2t2p wrote:
| I can turn any collection to list like that:
|
| public <Z, T extends Collection<Z>> List<Z> process(T
| collectionOfInteger) { return collectionOfInteger.stream()
| .collect(toList()); }
| mrkeen wrote:
| Great!
|
| These are the three implementations I want to hide behind
| a single abstraction: //
| java.util.Optional public <U> Optional<U>
| flatMap(Function<? super T, ? extends Optional<? extends
| U>> mapper) //
| java.util.concurrent.CompletionStage: public <U>
| CompletionStage<U> thenCompose(Function<? super T, ?
| extends CompletionStage<U>> fn); //
| java.util.stream.Stream: <R> Stream<R>
| flatMap(Function<? super T, ? extends Stream<? extends
| R>> mapper);
|
| Any suggestions?
| p2t2p wrote:
| Also I don't understand why would you need HKT here. I
| don't see language limitation here, I see poorly designed
| inheritance in the standard library. They should've
| introduced "FlatMappable" type and make Option and Stream
| extend it. CompletionStage, I'm torn on it, on one hand
| yes, it is a flatMap essentially but semantics is a bit
| different...
| p2t2p wrote:
| Oh my god, there's more to that, Optional is a class, not
| an interface and it's final :facepalm:
| mrkeen wrote:
| I've made my peace with those aspects of the libraries.
| I'm happy to wrap the standard classes in MyOption,
| MyStream, etc. Then I can extend FlatMappable myself. I
| just don't know how to declare and implement FlatMappable
| in a sane way (preserving type information, not needing
| casts, etc.)
| Joker_vD wrote:
| Sure: public interface FlatMappable<T>
| { <U> Optional<U> flatMap(Function<? super T,
| ? extends Optional<? extends U>> mapper); }
| public class FlatMappableOption<T> implements
| FlatMappable<T> { private final Option<T>
| value; public
| FlatMappableOption<T>(Option<T> value) {
| this.value = value; } <U>
| Optional<U> flatMap(Function<? super T, ? extends
| Optional<? extends U>> mapper) { return
| value.flatMap(mapper); } }
| // similar wrappers for CompletionStage and Stream
|
| Now whenever you want to pass a
| Stream/CompletionStage/Option to something that accepts
| FlatMappable, you either a) already has it wrapped in
| FlatMappable, so pass that wrapper in; or b) has a naked
| value of known type, so wrap it in the propper wrapper
| class and pass the resulting wrapper in.
|
| Of course, it would be nice to have this wrapping done
| automatically instead of manually, but that's pretty much
| how it's actually implemented behind the scenes
| (dictionary passing, or look at Go's way to wrap things
| inside interface{}).
| p2t2p wrote:
| I'm not sure if I catch your drift, but if I do:
| public <T, Z, F extends Function<? super T, Z>> Z
| apply(Function<F, Z> target, F fn) { return
| target.apply(fn); } @Test
| public void test() throws Exception {
| Stream<String> stream = Stream.of("foo", "bar", "baz");
| stream = apply(stream::flatMap, s -> Stream.of(s + "_a",
| s + "_b"));
| System.out.println(stream.collect(toList()));
| Optional<String> bean = Optional.of("bean");
| bean = apply(bean::flatMap, b -> Optional.of("soy"));
| System.out.println(bean);
| CompletableFuture<String> future1 =
| CompletableFuture.supplyAsync(() -> "hello");
| CompletableFuture<String> future2 =
| apply(future1::thenCompose, string ->
| CompletableFuture.supplyAsync(() -> string + " world"));
| System.out.println(future2.get()); }
|
| Output:
|
| [foo_a, foo_b, bar_a, bar_b, baz_a, baz_b]
|
| Optional[soy]
|
| hello world
| mrkeen wrote:
| This is interesting stuff.
|
| I'm trying to figure out how to refer to flatMap directly
| from the abstract function, e.g.
| flatMapTwice(x, fun) { return
| x.flatMap(fun).flatMap(fun); }
|
| or chain(x, fun1, fun2) {
| return x.flatMap(fun1).flatMap(fun2); }
|
| It should also preserve the type information (just like
| you did above). I don't want the caller to need to
| downcast from FlatMappable.
|
| It doesn't need to be x.flatMap(f) - I'd be interested
| seeing a flatMap(x, f) version.
| [deleted]
| kasperni wrote:
| A 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
| _old_dude_ wrote:
| Very 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 wrote:
| There is no next step for Java, because of backwards
| compatibility this is as good as it gets.
| Felk wrote:
| While 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 wrote:
| I 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 wrote:
| This has passed me by, what's happening?
| BenoitP wrote:
| Not 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
| dep_b wrote:
| I 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.
| skocznymroczny wrote:
| The relative simplicity of the language allows it to have
| excellent IDE support. I can select a class name, rename it,
| and have it renamed in all files that use this class. And the
| IDE knows that this actual class is being used, not another
| class from another module that has the same name, and that it's
| not a string with the same value as the class name. With
| languages like C++ all you can do is grep and cry.
| Semaphor wrote:
| OP mentioned C#. Exactly the same is possible there.
| gmueckl wrote:
| Yes and no. The C# language does have conditional
| compilation, which is modelled after the C preprocessor.
| That can interfere with refactoring and limit its accuracy.
| The good thing is that this mechanism is rarely used in
| practice.
| shellac wrote:
| Does the LINQ expression tree stuff complicate things? I
| don't know how that works with respect to parsing.
| northwindfoo wrote:
| Visual studio has c++ symbol rename, including class names.
| Has had it for a while as well. Fairly reliable, though
| occasionally it does fail, loudly.
| ludovicianul wrote:
| Why does it always has to be language 1 vs language 2? "Better"
| is hardly something objective about languages. This is why
| people are still building new languages every year. To make
| things "better", although ultimately a bunch of others will
| find quite a big list of why they don't like it. Just pick
| whatever language you like. As long as you have good tooling
| and community around it, it won't be neither the best nor the
| worst choice... It's just "a choice"... Projects hardly fail
| because of the language itself (although there are some well
| known failures with dynamically typed languages). It's mostly
| bad architectural or business decisions...
| hackerbrother wrote:
| I think that in comparison, what happened with Javascript has
| been great honestly. People have been completely stuck with
| it, so we've built a great server side (Node.JS / npm / yarn)
| and client side (React, Vue, Typescript, Babel) ecosystem
| around it. I think great things can happen if you stick with
| a language and work with that limitation.
| thrower123 wrote:
| Things will be really exciting once WebAssembly finally
| breaks through (Next year in Jerusalem!...) and we're not
| forced to compile better programming languages to
| Javascript.
| davnicwil wrote:
| > a solid argument why the language itself is nice to work with
|
| Java with IntelliJ is _awesomely_ productive. You barely have
| to type anything beyond new variable / field names, everything
| else is generated or tab completed. Refactoring is a breeze.
|
| That, times 'worse is better' - it's the language and toolset I
| already know for the types of things it's good at. I have no
| doubt C# is comparable or better at most things, but probably
| not so much so that it is worth switching.
| Semaphor wrote:
| > Java with IntelliJ is awesomely productive.
|
| They have a C# IDE (Rider) now, based on IntelliJ. While it
| was originally the only non-Windows C# IDE, I and others have
| switched to it from Visual Studio (which is almost as good)
| even on Windows.
|
| > I have no doubt C# is comparable or better at most things,
| but probably not so much so that it is worth switching.
|
| I'd say you are right. Now. 10 years or so ago (6/7/8 times)
| I'd have disagreed, C# avoided many of the mistakes* Java
| made and was able to become far more pleasurable to use, it
| took some time for Java to catch up again.
|
| *: Mistakes only in hindsight
| pjmlp wrote:
| > But never really a solid argument why the language itself is
| nice to work with.
|
| If you were trying to write portable C++ code in 1996 you would
| get it, specially when using each OS specific C++ compiler
| provided by the platform vendor.
| codeulike wrote:
| Exactly, at the time it was invented, Java was a massive
| improvement on the incumbents in all sorts of ways
| AnimalMuppet wrote:
| We cross-compiled to get gcc on every platform. Even then, it
| was still: #ifdef _AIX ...
| #else ifdef SGI ... #else ifdef WINDOWS
| ... #else // everything else ... #endif
|
| Shudder.
|
| But the other thing that Java had is the _library_. Compared
| to C++ 's standard library in 1996, it was a revelation.
| thrower123 wrote:
| From what I have seen, I'd probably pick Kotlin if I had to be
| on the JVM. Seems to strike a nice balance between sanding off
| the rough edges of Java syntax, and still being conventional
| and blub enough that it won't put people off.
| xwolfi wrote:
| Not sure everyone agrees but each time I've used type
| inference language (really just Groovy to be honest, but many
| many many different teams and companies), it ended up with an
| enormous mess of code that the brain of all of us devs had to
| parse themselves. We rolled back to Java many such critical
| paths just to be able to maintain them.
|
| My little pitch when starting a migration project in a
| distressed no-type language team is to make them read the
| code and explain it, while asking about the type of objects
| they use and show them when they read it's their brain
| parsing it with high effort. If they de-optimize and just
| write the types more often, it becomes much clearer longer.
|
| You can type usually in those language but often people want
| to use the "proper way" as shown in ultra simplistic examples
| in manuals for sales pitches and end up thinking the right
| way to code is to write as little as possible (combined with
| the no-comment belief they have but don't map to "no comment
| because clear enough code").
| thrower123 wrote:
| I mean, Groovy is terrible, and there is not very good
| tooling for it.
|
| That's not the case for Kotlin, that has the full weight of
| JetBrains behind it.
| dboreham wrote:
| Are you assigning any cost to : Kotlin is not Java and
| therefore new tools, developer training, etc are required?
| I'd want Kotlin to be significantly better than Java to
| justify the fact that it's not Java, if you see what I mean.
| dep_b wrote:
| You can write Java in Kotlin in less than a day.
| xwolfi wrote:
| Well I may try ! I'm not very religious, I used Java for
| everything since I've started programming and I work in low
| latency in an investment bank now. I adore Java, it's my truly
| native programming language, I try to know all of its quirks,
| study each new version and know still not enough to satisfy my
| love of it.
|
| I also did a lot of C# to help on a GUI optimization project
| (because doing low latency if the GUI freezes every 10 minutes
| isn't great), and I was really surprised by how good it was so
| I wouldn't disagree it works nice.
|
| BUT I like that Java works simply in linux, I like that it
| didn't yet got contaminated by all the crazy constructs from
| elsewhere (Groovy grr), I love the tradition around the syntax
| (I can't stand C# quirks sometimes). I do HATE with passion the
| meaningless generics, and I wish we'd ditch backward compat to
| steal it all form C++ templates.
|
| I enjoy more than the language syntax itself that is close to
| most languages I like (Javascript, C#, C++), the team spirit
| around it. Believe me, it's much easier to use and understand
| maven (or maybe gradle who starts to get dangerous in real
| world projects where you can't afford 2 weeks of reverse
| engineering a madman's build script) than it was nugget, it's
| easier to use IntelliJ than to receive yet another stupid email
| from compliance about a Visual Studio license missing, it's
| nicer to build a jar and run it than to go through all the
| kinks of exe files... I dunno I may have started from Java and
| got to C# and done the opposite of your journey, but while I
| agree C# has superior features in some aspects (but sometimes
| they chose mess vs safety) I just wasn't convinced it could
| work for something more critical where you must do things as
| simple as you can, as clear as you can.
|
| And let's not even start on C++ who's superior in every
| conceivable way except that it encourage, or doesn't
| discourage, every team I ever meet to create unbearable messes
| they can't fix, so focused they are fixing problems we can't
| even imagine in Java for reasons we can't comprehend our
| company even accepts to finance :D
| shellac wrote:
| Your first paragraph is a fair encapsulation of what Java was
| intended to be from 1994: a mullet of a language that is
| deliberately unexciting at the language end, but brings in a
| number of (at the time exotic) features at the VM end.
|
| Things like GC, reflection, runtime loading of code, that were
| very familiar from more academic languages at the time.
| overtomanu wrote:
| Backward compatibility is one of the biggest reasons
| mrkeen wrote:
| Does C# handle generics better than Java?
| LandR wrote:
| C# generics are reified.
| accountLost wrote:
| You 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 wrote:
| There is a way-ish, which is passing a Class<T> as an
| additional parameter and doing clazz.newInstance().
|
| Definitely not pleasant though.
| Felk wrote:
| For that particular use case it may be better to pass a
| constructor reference / new instance supplier to not rely
| on reflection.
| Felk wrote:
| As "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
| paavohtl wrote:
| C# implements proper reified generics. Generic types
| parameterised with different types are actual types in C#,
| while in Java generics is basically just syntax sugar for
| avoiding type casts. Each element in a List<byte> in C# takes
| 8 bits, while in Java each element in a ArrayList<Byte> is
| actually just an Object and therefore is a pointer (64 bits)
| to a separate allocation.
| kaba0 wrote:
| But at the same time, reified types will create a separate
| object for each template type, making some optimizations
| happen only for a type that was used often. While in Java,
| ArrayList for example will benefit regardless of the
| concrete type.
| HappySweeney wrote:
| Java has a much better AOP story, but that will likely change
| once source generators become more mature.
| xwolfi wrote:
| I find AOP dangerous. I love the abstract concept, but each
| time I used it myself I ended up creating a mess that I had
| to painfully rollback just to produce less insanity for my
| poor colleagues.
|
| I'm sure it's me but do you use it yourself and why ? Don't
| you get lost in the indirections in big projects "oh shit
| where is that thing again that auto inject itself here" ?
| xwolfi wrote:
| One 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 :(
| datavirtue wrote:
| This is a great write-up. Accessible but thorough.
| ChrisArchitect wrote:
| alternate url also submitted 9 months ago, I dunno
|
| https://news.ycombinator.com/item?id=23621185
___________________________________________________________________
(page generated 2021-04-01 23:03 UTC)