Java is not trying to "keep up." It is intentionally slow-moving and conservative (this design goal was set by James Gosling when Java was first created), and only adds features once they have been proven in other languages for a while.
Java is not trying to "keep up." It is intentionally slow-moving and conservative (this design goal was set by James Gosling when Java was first created), and only adds features once they have been proven in other languages for a while.
On the other hand, what I consider a major mistake from Java side was ignoring value types and AOT compilation since it's inception.
Had Sun blessed such features since the beginning, and many use cases for C and C++ wouldn't be necessary.
As to baking variance into the runtime, I think this is just a bad idea, which is so far used only in C++ and .NET, two languages/runtimes with notoriously bad interop (it's not just Scala; Python and Clojure have a similarly bad time on the CLR, as would any language not specifically built for .NET's variance model). It is simply impossible to share a lot of library code and data across languages with different variance models once a particular one is baked into the platform. This is too high a price for a minor convenience.
Specialization for value types (which are invariant), is another matter, and, indeed, it is planned for Java. Perhaps some opt-in reification for variant types has its place, but not across the board. I am not aware of other platforms that followed in .NET's misplaced footsteps in that regard. Those that are known for good interop -- Java, JS and LLVM, don't have reified generics.
What's worse is that it's a mistake that cannot be unmade or resolved at the frontend language level. Even Java's big mistakes (like finalizers, how serialization is implemented, nullability and native monitors) are much more easily fixed.
There's a reason java had built-in value types from day 1, because it made sense even back then.
Frankly, I think both java and C# kind of got this wrong. There was an overreaction against the C/C++ of the day, and whereas the GC turned out brilliant, the idea that it's not even necessary to express the notion of references/pointers/values etc. was too much; and the idea of a single type system root (object) is similarly dubious, and then particularly the idea that that root type isn't the empty type. Object has semantics, and that was a mistake, because it contributes to the bloat. I'm totally happy with ignoring those features 99.9% of the time, but having them completely unavailable makes those 0.1% cases extremely expensive. (I mean, I think those things are slightly changing, but it's slow going).
AOT compilation not so much, given the NGEN constraints.
However they got it both wrong, considering CLU, Modula-3, Delphi and Eiffel are considered influencial languages on their design.
That was necessary for performance back then. User-defined value types weren't, and Java has done well without them.
> Object has semantics, and that was a mistake, because it contributes to the bloat.
I think most of the RAM bloat is due to the GC trading off extra RAM for speed rather than object headers, and I'm not sure trading off complexity for headers was right 25 years ago (JS is doing fine on the client without value types). What changed was the performance characteristics.
As to object semantics, it may be a fixable mistake. The goal is to get value types without today's object semantics while preserving a single class hierarchy at the same time. The Valhalla team thinks that's achievable.
All of them refer that having value types alongside GC had a relevant impact improving performance.
All systems designed before Java was a thing.
Or since you refer to JS, the paper about SELF's design.
Even Dylan was designed with AOT/JIT and value types support, which is relevant here given that its domain was being a systems language for the Newton. That politics killed it is another matter.
I don't know why there was no emphasis on AOT back then. I guess they started with interpreter/JIT, and then there just wasn't much demand for AOT until now.
QuickBasic supported value types and AOT to native code, and while Visual Basic used P-Code, version 6 introduced a proper AOT native compiler.
Modula-3 was also a big influence, at least accordingly to some papers.
There was surely demand for AOT, given that most commercial JVMs had it in some form or the other since 2000.
Even Sun actually supported it in Java Embedded variant for OEMs, probably grudgingly.
Common Lisp certainly has support for value types.
As for AOT, there may not have been sufficient demand from Sun/Oracle. I only joined relatively recently, but we generally do expensive things only if we believe they have a huge benefit or in huge demand, and we believe it can be long-lasting. The assumption is that any new feature will require maintenance for 20 years, taking away resources from other things. So if something is expensive, even if it's cool or some people could find it very useful -- we don't do it. The assumption is that the ecosystem is large enough that others can, and will.
I can check the respective manuals if you wish.
Yep, I did VB programming for a short while.
And please note that even though my focus is now elsewhere, Java is one of my favourite eco-systems.
As a peasant I just wished that Java 1.0 was more like Go, given the existing alternatives back then.
So it kind of stayed as a pet peeve of mine.
Same applies to .NET, just in a different way.
However due to the hardware architecture changes and new kids on the block, it is starting to be an issue.
I keep wishing to see them arrive, have watched all the JVM Language Summit, Devoxx and JavaONE talks about them.
Meanwhile I can already enjoy them elsewhere. :(
That's perfectly fine. We think that our priorities are right for the workloads Java is used for (e.g. people care more about a low-latency GC like ZGC, and deep low-overhead in-production profiling, like JFR, than about AOT).
Value types were pretty much obvious as necessary.
More so when one dives deep into how languages like CLU and Mesa/Cedar were designed.
Having a AOT support doesn't preclude having a JIT as well, like Common Lisp or Eiffel already had in 1995.
Gosling said that his goal was to have nothing you can somehow live without (I don't know how well early Java lived up that ideal, but that was the ideal). Hardware changes made user-defined value types absolutely necessary for workloads Java wants to target.
If I recall correctly it even depended on WINE.
Are there any plans to fix those?
C# i s one of the best dev experiences in any language/IDE
[1]: Maybe not C# programmers, but there are easier ways to do a single-language runtime.
Go's goroutines seem okay - but I don't like how much control they take away from the programmer. For example, last year I worked on calling-into a black-box C DLL from a Go program and we learned the C DLL had code that was actually simply terminating the thread inside of it (by design!) because the author of the C DLL assumed ownership of the thread. That caused a problem for us because Go's goroutines are scheduled by the Go runtime and it will never let you give-up ownership of a Go thread - and I couldn't see how I could use my own thread (e.g. getting a thread from a native OS call to keep it outside of Go's control) with goroutines. The project was almost DOA after we learned this, fortunately we convinced the author to always return instead of killing the thread. I'm not sure if anything's changed in Go since then that would have made things easier for us. But since then we haven't used Go for anything new. The only reason we used Go was because it gave us binaries that "just worked" for Windows, macOS and Linux without having to worry about Java, .NET and other dependencies - but I wasn't happy about the ~20-30MB-sized executable output.