Java gets a bad rap from people that used it late 90's through early 2000's and got burned out by XML and design pattern heavy frameworks but its a lovely language that with a little discipline can be used to create very lean looking code. Go is one of the HN darling languages and I work in Go everyday for work (and generally like it), but I really wish I could reach for Java most days.
"Go is one of the HN darling languages" It's def not the case, I spend too much time here and on Reddit and people are always complaining about Go ( generics, errors, type system etc ... ), if you want the godly language it would be Rust, anything about Rust will be upvoted. As for Java, it's a good language / runtime that is overly complicated behind layers of abstraction. Take Spring for examnple, magic everywhere,…
A categorized list of all Java and JVM features since JDK 8 to 16
211–220 of 243 posts
Re: A categorized list of all Java and JVM features since JDK 8 to 16
#212I was programming in Java before generics came out. While generics were a very big upgrade, it was such a disastrous mistake to go for type erasure, because Java has a bifurcated type system. As we all well know, you can't be generic over a primitive type, for exactly this reason. I knew then and have minefield-of-rakes stumbled my way through every single consequence of that decision and still think it was wrong. Th…
Firstly, Java's generics did extend the class file format, quite significantly. Lots of metadata about generics and type variables makes it into the class files which is why you can reflect over them. It requires a gross trick involving creating anonymous objects that subclass a TypeHolder or TypeToken style class but you can do it because the data is there.
What they didn't want to do was break existing code and tie the JVM too deeply to their specific choice of generics. The downside is sometimes you can't do stuff you want to do, like overload a method in ways that only differ by a type variable. The upside is that there are still tons of libraries out there that are useful which at least internally have pre-generics code: backwards compatibility has real value. Also, other languages like Scala and Kotlin were able to try out different approaches to generics. Kotlin in particular improves on Java's existing generics and that's possible partly due to erasure.
Also, truly reified generics is really hard. Look at Valhalla and the "parametric JVM" documents. Doing it well involves a lot of complex design choices and support infrastructure. Most languages struggle with this. For instance it's a big part of why C++ libraries find it hard to export stable ABIs.
Re: A categorized list of all Java and JVM features since JDK 8 to 16
#213Earlier quoted context omitted.
I don't know about Ada, but I enjoy Rust's strictness when it comes to numeric types. > Java-style wrapping integers should never be the default, this is arguably even worse than C and C++’s UB-on-overflow which at least permits an implementation to trap. EXACTLY. It's f-ing stupid. C's excuse was compilers doing magic on UB or whatever. Java has no such excuse. They just wanted it to behave the same as C/C++ to attr…
> I don't see how const and immutability align with Java's original philosophy of being object-oriented, which is all about opaque objects that control internal mutable state. That's an interesting point, but an object presents an interface and promises to deliver some particular behaviour. A const system is a way of letting the type-system formalise some of an object's promises, no? I don't think this is particularl…
A C++ style const system would seem to be compatible with that.
And, in every practical sense, I would love such a thing existing in Java. I don't give a crap about whatever "OOP philosophy" and purity, even if my statement were correct/true.
However, (and this is just navel-gazing, honestly), adding const to object methods is exposing information about its internal state. That's not very "objecty" in the Alan-Kay-ish, Actor-model-ish sense. An object's internal state is "none of your business."
> Java's String class doesn't let me access its internal character array, but it still matters to me that it promises never to mutate it, nor to let anyone else mutate it (at least ignoring reflection).
I feel like this is a little different. Strings in Java are technically a class, but they're really treated like primitives (evidenced by the fact that literals are magically made into String objects).
But, it doesn't really matter. I agree. It's great that String promises to be immutable.
I'd argue that immutable class instances aren't really "objects" anymore- they're just (possibly opaque) data types.
Re: A categorized list of all Java and JVM features since JDK 8 to 16
#214Earlier quoted context omitted.
Briefly, that a thread cannot escape a scope. All threads must be joined before leaving the scope. Some resources: https://wiki.openjdk.java.net/display/loom/Structured+Concur... https://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part2.... https://vorpus.org/blog/notes-on-structured-concurrency-or-g...
Not exactly. That's the programming rule for structured concurrency which is a very simple bit of logic added on to the ExecutorService class. Loom itself is just about making threads super cheap/fast. You can use new cheap threads in exactly the same way as normal and nothing will complain. You can also use structured concurrency with old threads, and again, nothing will complain. And you don't need Java support for…
The discussion further down about "scope variables" foreshadows making structured concurrency more strongly, directly supported by the language's runtime:
> What about inheritance? Because SVs are immutable, and because structured concurrency also gives us a syntax-confined thread lifetime, SV inheritance fits structured concurrency like a glove
Re: A categorized list of all Java and JVM features since JDK 8 to 16
#215Earlier quoted context omitted.
> I suspect this would be disastrous for performance. I believe Haskell uses a similar approach though. > > Sometimes you want to store 20 million very small values in an array. Forcing use of bigint would preclude doing this efficiently (in the absence of very smart compiler optimisations that is). I suspect that it would. I also suspect that I don't care. :p We're talking about Java. Yes, you can write high-perform…
I suspect the performance penalty would be so severe it might undermine the appeal of Java. I don't have hard numbers on this though, perhaps optimising compilers can tame it somewhat. Presumably Haskell does. A more realistic change might be to have Java default to throwing on overflow. The addExact methods can give this behaviour in Java. In C# it's much more ergonomic: you just use the checked keyword in your sour…
I also agree that a "more realistic" option is to just throw on overflow by default, the same way we throw on divide-by-zero.
But that won't happen either. :/
Re: A categorized list of all Java and JVM features since JDK 8 to 16
#216Earlier quoted context omitted.
Well said :) . Spring looks so much as to show how useful ideas can be misapplied with catastrophic results. For example, liberate encouraging of dependency injections leads to multitude of interfaces which are only ever implemented once by a production code class, and maybe one more time by a test class, even though Java has all methods virtual and testing could be done without requiring the interface.
It's reasonable to provide a single implementation of an interface, if the goal is to facilitate dependency injection for that component. The problem I find with Spring is that it is designed for dependency injection at all levels of its architecture, leading it to be one of the ultimate examples of Ravioli Code. https://wiki.c2.com/?RavioliCode DI is a powerful concept, but Spring projects rely on DI in such a gener…
You don't really need dependency injection if there is only single choice of what to inject. You can just refer in code to the only possible component.
Re: A categorized list of all Java and JVM features since JDK 8 to 16
#217Earlier quoted context omitted.
> I don't see how const and immutability align with Java's original philosophy of being object-oriented, which is all about opaque objects that control internal mutable state. That's an interesting point, but an object presents an interface and promises to deliver some particular behaviour. A const system is a way of letting the type-system formalise some of an object's promises, no? I don't think this is particularl…
I get what you're saying and I don't really disagree with you. An object's methods are an interface and its method signatures are a contract about what "messages" (in Alan Kay parlance) it will accept and return. A C++ style const system would seem to be compatible with that. And, in every practical sense, I would love such a thing existing in Java. I don't give a crap about whatever "OOP philosophy" and purity, even…
An object's state is my business, as immutable objects can be used in ways that mutable ones cannot. They can be passed to arbitrary functions with no need for defensive copying. They can also be useful in concurrent programming. None of that means breaching the separation of interface and implementation.
> Strings in Java are technically a class, but they're really treated like primitives (evidenced by the fact that literals are magically made into String objects).
Immutable objects can generally be treated as values, that's their charm. There's a good talk on this topic, The Value of Values. [0]
> immutable class instances aren't really "objects" anymore- they're just (possibly opaque) data types
They're certainly still objects. The essence of object-orientation is in dynamic dispatch, not in stateful programming.
[0] https://www.infoq.com/presentations/Value-Values/ (Perhaps skip to 22:00 to get a sense of the general point.)
Re: A categorized list of all Java and JVM features since JDK 8 to 16
#218Earlier quoted context omitted.
Not exactly. That's the programming rule for structured concurrency which is a very simple bit of logic added on to the ExecutorService class. Loom itself is just about making threads super cheap/fast. You can use new cheap threads in exactly the same way as normal and nothing will complain. You can also use structured concurrency with old threads, and again, nothing will complain. And you don't need Java support for…
No, not exactly. Thus ever the fate of tl;drs. The discussion further down about "scope variables" foreshadows making structured concurrency more strongly, directly supported by the language's runtime: > What about inheritance? Because SVs are immutable, and because structured concurrency also gives us a syntax-confined thread lifetime, SV inheritance fits structured concurrency like a glove
Re: A categorized list of all Java and JVM features since JDK 8 to 16
#219I was programming in Java before generics came out. While generics were a very big upgrade, it was such a disastrous mistake to go for type erasure, because Java has a bifurcated type system. As we all well know, you can't be generic over a primitive type, for exactly this reason. I knew then and have minefield-of-rakes stumbled my way through every single consequence of that decision and still think it was wrong. Th…
It's not quite like that. Firstly, Java's generics did extend the class file format, quite significantly. Lots of metadata about generics and type variables makes it into the class files which is why you can reflect over them. It requires a gross trick involving creating anonymous objects that subclass a TypeHolder or TypeToken style class but you can do it because the data is there. What they didn't want to do was b…
IMHO it was still a major design mistake that has cost everyone else more time in the end. A classic near-term/long-term miscalculation. For a counterpoint, C# introduced generics and rewrote the class library. They're in the bytecode, not just metadata. The VM dynamically specializes JIT code as necessary, and shares equivalent specializations to avoid code explosion.
> Also, truly reified generics is really hard.
I think this statement is false. It's not intrinsically hard; it's only hard because of a lot of other constraints. For example, Virgil has "reified"[1] generics since 2.0 and I just use monomorphization. MLton did the same, 20 years back. Code explosion isn't that bad for medium-sized programs.
[1] "reified" implies there is a runtime representation, which is not really what's going on. With static specialization, it's possible to completely compile away any additional metadata representation, as it either becomes implicitly part of a function specialization or the class metadata for specialized classes.
The only real reason I see to not use monomorphization is if you have polymorphic recursion, or first-class polymorphism. Virgil doesn't allow either of those.
Re: A categorized list of all Java and JVM features since JDK 8 to 16
#220Earlier quoted context omitted.
> I'll admit that I have a glaring experience gap with .NET languages, so I can't honestly say anything about C# and F#. C#/.NET comes with language-level mutexes (`lock`) and the .NET library has thread-safe generic collections (ConcurrentDictionary, ConcurrentBag) and true immutable collections (ImmutableArray, ImmutableList, ImmutableDictionary) with optimized copy operations (e.g. ImmutableList.Add is O(1), but I…
That's good to hear. Java/Kotlin also have mutexes- just not as language built-ins (well, it does have `synchronized`). They also have a ConcurrentFoo set of collections as well. And actually an ImmutableMap (but I don't see ImmutableList, etc. Why?). The "problem" is that they're opt-in. I spent years writing multi-threaded C++. But I've become very spoiled with modern languages that make concurrency safe(r)-by-defa…
.NET doesn't have an ImmutableList either (the ImmutableBag type is an unordered collection). This is because unlike with hash-tables you always need to lock the entire structure when mutating a List/Vector (with hashtables you only need to lock the specific bin/bucket).