A great read for folks wondering why Java uses type erasure instead of “reified” generics. For the unaware, that means that a List<Integer> is a List<Object> at runtime. I had always wondered about it and why they didn’t take the alternative route. For context, C# does have reified types so the actual type parameter is available at runtime.

I personally love reading in depth discussions about counter intuitive engineering decisions like this.

  • Asifall@lemmy.world
    link
    fedilink
    arrow-up
    1
    ·
    2 years ago

    This is an interesting read, but it doesn’t really live up to the title. I can see how erasure was the best compromise at the time, but it’s still a compromise.

    • Vipsu@lemmy.world
      link
      fedilink
      English
      arrow-up
      2
      ·
      1 year ago

      Yeah, this quote pretty much sums it up

      C# made the opposite choice – to update their VM, and invalidate their existing libraries and all the user code that dependend on it. They could do this at the time because there was comparatively little C# code in the world; Java didn’t have this option at the time.

      Which tells me that it was mostly about maintaing backwards compatibility with legacy code. Having used C# and Java for years the effect of type erasure seems to be bunch of silly @SuppressWarnings("unchecked") annotations in code and classes that mostly just exist to encapsulate a list of objects. With C# I create my own generics all the time but with Java I tend to avoid doing that like a plague.

      I do however have to admit that I skimmed through most of the article because it’s just too difficult to read with its complex vocabulary (full of words like pragmatic, ubiquitous, fictions, heterogeneous, etc) combined with a lot of technical jargon about lower level languages. Guess reading and actually really understanding the article would be easier and less time consuming if I was native english speaker but at its current form the article is far from being accessible or succesful explaining why one should love type-erasure.

    • JackbyDev@programming.devOPM
      link
      fedilink
      arrow-up
      0
      ·
      2 years ago

      Yeah, this is an example I talked about in another comment here but I can be more concrete. This and code like it is why I usually wondered why erasure happens at all. In the Jackson framework to convert JSON to a class you pass in the type like MyClass.class but because you can’t pass in parameters you’d have to do List.class. Jackson has this method to handle such situations. It uses the TypeReference class which takes advantage of Java storing type parameters for anonymous classes. The Javadoc for that class mentions this blog which is sort of the de facto source for getting around this limitation. Essentially the code you write is like this,

      readValue(someJson, new TypeReference<List<Integer>> {});
      

      You make a new, anonymous implementation of TypeReference<T> and T is known at runtime.

      I haven’t looked into why Jackson has to do it that way but my best guess is the proper way would be inconvenient.

      • Tom@programming.devM
        link
        fedilink
        arrow-up
        2
        ·
        2 years ago

        Ah, that makes sense!

        I guess I haven’t really run into many examples like this. The times I’ve run into code where the former developers clearly struggled with handling types correctly has nearly always been their own fault (bad interface, bad organization of data, etc)

        • JackbyDev@programming.devOPM
          link
          fedilink
          arrow-up
          2
          ·
          2 years ago

          Yeah, agreed. My first project as a junior dev was on Java 6 using something written before Java 5 that they sort of slapped generics all over for no apparent reason. So many warnings lol.

  • Knusper@feddit.de
    link
    fedilink
    arrow-up
    0
    ·
    2 years ago

    I’ve always wondered, if it’s also just less pain when you write plain/idiomatic Java.

    I write mostly functional Scala with lots of message passing and such, so data types often move through interfaces where their type may be lost and then we do lots of pattern matching, where missing runtime types come up on quite a regular basis.

    I’d say probably once a week, I have to write or come by an ugly portion of code where we had to manually pass around type information and do explicit casts to make it all fit together.

    • JackbyDev@programming.devOPM
      link
      fedilink
      arrow-up
      0
      ·
      2 years ago

      I’m not familiar with Scala, but doesn’t it have a different form of generic typing? Like isn’t there a way to explicitly say if you want co- or contravariance? Maybe it’s not totally compatible.

      But yeah, even as an exclusive Java developer the only time I have to do something like this is when you’re doing something like deserializing JSON and need a type parameter. As an example you can tell it, “Hey, I expect this is LocalDate.class” but if you need something like a List<LocalDate> you can’t do that with the .class syntax. Weirdly, anonymous inner classes do store type parameters so the way most frameworks handle it is something like new TypedParamter<List<LocalDate>> {}. I’m not sure if there is a way for frameworks to get around it, I just know that’s the only real time I see it.

      • Knusper@feddit.de
        link
        fedilink
        arrow-up
        0
        ·
        2 years ago

        Scala does have a way of specifying co-/contravariance, but Java actually does have that, too. In Java, you write <? extends T> for covariance and <? super T> for contravariance. Well, and generally, Scala’s generics are compatible with Java’s. It’s quite common to use Java libraries in Scala.

        One example where type erasure causes problems (which should be the same in Java):
        Imagine, you’re managing sensors and all of those sensors have a generic to remember what element will be produced by them: Sensor<Integer>, Sensor<String> etc.
        If you want to keep all of those Sensors in one big list/map, you end up with a Sensor<Object> when you take them back out.

        To retain type information, you have to put them into individual lists or somehow place a runtime type next to each element in the list, from which you can determine what to cast to.

        I guess, in languages without type erasure, it doesn’t let you place a Sensor<Integer> into the same list as a Sensor<String> to begin with, as those are strictly different types.
        But of course, those languages may offer ways of doing type erasure anyways, and obviously, you can fall back to a common interface/supertype, if the types have that.

        • JackbyDev@programming.devOPM
          link
          fedilink
          arrow-up
          1
          ·
          edit-2
          2 years ago

          As a heads up, idk if it is just the Jerboa app or Lemmy but I your type params on Sensor were being interpreted as HTML tags and not rendered. The ones in the first paragraph are fine though.

          Can we use <b>raw HTML?</b>

          Edit: looks like it just gets blocked and not read.

          Edit 2: Looks like Jerboa and the browser display this differently actually lol

          • Knusper@feddit.de
            link
            fedilink
            arrow-up
            1
            ·
            2 years ago

            Funnily enough, I typed that one in the Jerboa app, but yeah, it’s not rendering for me either. 🙃

            • JackbyDev@programming.devOPM
              link
              fedilink
              arrow-up
              2
              ·
              2 years ago

              I opened a GitHub issue. I think it’s probably just a config thing as they are both based on the CommonMark spec. Or maybe a nug with one of the markdown libs themselves.