224 comments

[ 2.1 ms ] story [ 279 ms ] thread
When I saw sequenced collections earlier I didn’t like the design but I completely approve of the latest revision. One nice thing about the process they use to develop Java is that they really do work and rework new features to make them great.

I just wish that instead of Streams they’d made something more like

https://github.com/paulhoule/pidove

With the possibility of making something more fluent and less lispy.

Pidove sounds really awesome. I'm totally going to give that a try!
It has a sibling project which is still half-baked

https://github.com/paulhoule/ferocity

which is about developing a lispy DSL in which it is possible to write Java-in-Java to transform it to make syntactic macros. It's kinda crazy

https://github.com/paulhoule/ferocity/blob/main/ferocity0/sr...

and somebody might think it combines the worst of Java and Common LISP but I did enough work on it to be sure there were no major barriers. ferocity0 is a bootstrap implementation that it's possible to write a code generator that can generate code to make stubs for the standard library and write ferocity1 in ferocity0 and write ferocity2 in ferocity1 with the full power of code generation to hide the accidental complexity of Java... But other projects got in the way.

Looking at your examples, this looks like https://github.com/square/javapoet
Yeah, that’s very similar. Thanks for the link.

It’s got the difference though that they are using (mostly) strings to write the method bodies and my approach builds those up with the lispy DSL. The class/method/field definitions are basically the same. (ferocity contains three languages, one of expression trees, one of class definitions, another of compound statements that doesn't exist yet)

Mine can also run ‘lispy Java’ in an interpreted mode (as well as writing code that goes through javac) and I discovered the interpreter has a type system which is a little richer than the Java type system, namely I discovered (not invented) ‘quote’ and ‘eval’ so that expressions are a first class data type that can be manipulated…. I have to define some set of operators to make it easy to traverse and work on expressions which would make it easy to metaprogramming, probably taking back some of the verbosity that comes with the lispy java-in-java embedding.

I would already be happy if they provided some adapters for exceptions in lambdas, instead of us having to create our own, or use one of the several libraries that provide them.
I was wondering this morning, with regards to the pattern matching for switch:

Is there a performance consideration here? When using sealed classes, can the JVM do a better job optimizing pattern matches for switch? Are there also considerations with how it interacts with Project Valhalla?

The team evolving Java seem pretty good at evolving the language with higher level goals in mind, so I wasn't sure if there were interrelated factors here.

> When using sealed classes, can the JVM do a better job optimizing pattern matches for switch?

Yes! In the Pair<I> example from the JEP, if the number of subclasses of I is large enough, it may be worth generating a perfect hash function [0] to match the pattern in O(1) time instead of the naive O(n^2). This is only possible in the general case for exhaustive switch statements, which sealed classes allow for with instanceof-style patterns.

[0]: https://en.wikipedia.org/wiki/Perfect_hash_function

So, has perfect hashing dispatch like you're describing here actually been added (or planned) in the JIT?
modern java is a huge improvement over old java. switch pattern matching will be huge, this has been in preview for a long time
Look, I haven't done Java in more than 10 years, but I have done Scala. Honest question - isn't Java just trying to "steal" Scala's concepts and catch up to the "cool" languages?
All modern languages heavily borrow from each other’s latest iterations. In the case of Java though, playing catch up is by design since it’s intended to be a conservative/stable language.
Their philosophy is to "adopt" language features once they're well worn by other languages so they can learn from their mistakes / successes.
While philosophy is good, Java makes a very questionable syntactic choices when adopts that said features.

Pure slowness in how java develop feels like you have to wait 5 years to get something that other languages have, only to get it in the most aesthetically unpleasant way.

It seems like devs add unnecessary verbosity whenever they can.

Java adopted lambdas after many other languages, yet still decided that allowing to move last parameter closure {} outside of () is too radical, even though it is much more visually pleasant choice and quite common in other languages.

default methods in interfaces instead of static extensions. This one is controversial as static extension methods were not really common when java came up with this, but end result does not look impressive.

Same with their new sealed classes. They just chose the most verbose version they came up with.

Some inconsistency of choices also kinda baffles me. First they added support for skipping necessity of mentioning generic type inside <> during instantiation, only to introduce local vars later that require you to mention generic types within the same <>. Now you either mention generics by their full type always, or embrace the inconsistency and have it skipped when type mentioned in prefix and type it when using local vars. Or do not use local vars and have consistent codestyle with increased verbosity.

Java is still a good language, but it feels dated in syntax. TBH I have no idea why would anyone chose java in 2023 when there's kotlin, which not only fully covers the same functionality(okay, no pattern matching and no loom/valhalla until java merges it), but does it while being much more concise and readable.

I'd choose Java over Kotlin in 2023, in fact I'd do so most years. I'll pretty much take conservative language design over developer comfort every day of the week.
But you do not have to choose Java over Kotlin - you can use them both in the same project without any side effects.

This was by design for Kotlin, and is probably their smartest/best feature. All existing Java code/libs just work in Kotlin. Conversely, most Kotlin code/libs just work in Java, although some care needs to be made there.

Kotlin is amazing to use and read. For most things, the Kotlin version is easier to read and comprehend than the Java version in my experience.

As Java adds language features, Kotlin either gets them for free or already had them (and now can use native features instead of their own custom features).

In my case Kotlin was harder to read than Java, so it really depends on the person.

(Same thing with Groovy, but that one is even worse than Kotlin)

On the other hand Scala looks nice.

Kotlin adds Jetbrains only as IDE, additional build plugins, an ecosystem of Kotlin libraries for more idiomatic code, stack traces completly unrelated to Kotlin as JVM only understands Java, and it needs plenty of boilerplate to emulate co-routines and functions in JVM bytecodes.

Other than Android, there are no reasons for additional complexity in development tooling.

Most of your points are not really valid if you understand Kotlin. It's not different than understanding Java really...

> Kotlin adds Jetbrains only as IDE

Not true, you can use any IDE you want. Of course IntelliJ is the "blessed" IDE, but really, Kotlin is just a bunch of libs, any IDE will work.

> additional build plugins

I don't see why this would matter. Any non-trivial build is going to use a bunch of plugins.

> an ecosystem of Kotlin libraries for more idiomatic code

Which are optional.

> stack traces completly unrelated to Kotlin as JVM only understands Java

I don't know what you mean. The stack traces are from bytecode, which Kotlin compiles to just like Java. The stacks are identical...

> needs plenty of boilerplate to emulate co-routines and functions in JVM bytecodes

You do not write the boilerplate though. That's the difference. Of course all higher level languages with High Order functions are going to suffer this same issue. It's abstractions all the way down..

You probably already use Kotlin and don't even know it. The popular okHttp library from Square is Kotlin - but you'd never know that if you just used it in your Java project.

personally i think kotlin is fine, but when compared to modern java, i feel like i need to really see a quantum leap before i'd go all-in if i was running a business (to say nothing of the labor pool for kotlin vs java)
> to say nothing of the labor pool for kotlin vs java

This is the biggest issue, in my opinion. Although, if you have a java developer that really likes the higher order features that are being added, Kotlin might be a very easy switch (after some basic syntax learning).

The nice part is everything you already know about JVM performance still applies within Kotlin. So you're not starting over from square-one like you might assume.

> Not true, you can use any IDE you want. Of course IntelliJ is the "blessed" IDE, but really, Kotlin is just a bunch of libs, any IDE will work.

No I can't, because InteliJ is the only one that actually supports Kotlin.

Otherwise I would just be using Notepad++.

> I don't see why this would matter. Any non-trivial build is going to use a bunch of plugins.

It shows you don't work as build engineer.

> I don't know what you mean. The stack traces are from bytecode, which Kotlin compiles to just like Java. The stacks are identical...

Try to debug a Kotlin stacktrace with free functions and co-routines, and then try to tell the world it looks like what the Java compiler would generate.

> You probably already use Kotlin and don't even know it. The popular okHttp library from Square is Kotlin - but you'd never know that if you just used it in your Java project.

No I don't, because at my level libraries are validated and only internal repos are allowed in the CI/CD pipeline.

Also I no longer do native Android for work, other than mobile Web.

If you do not understand an ecosystem, then you will believe the things you are saying. Nearly everything you claim is simply not true, and demonstrates a lack of understanding more than anything.

You can indeed use notepad++ to write Kotlin. Nothing is stopping you.

Kotlin is not limited to mobile development either.

Kotlin is not limited to mobile development, it only matters on Android thanks to Google's shenanigans, which is a different thing.

And even despite of it, they were forced to update Android Java to keep up with the JVM ecosystem.

> The next thing is also fairly straightforward: we expect Kotlin to drive the sales of IntelliJ IDEA. We’re working on a new language, but we do not plan to replace the entire ecosystem of libraries that have been built for the JVM. So you’re likely to keep using Spring and Hibernate, or other similar frameworks, in your projects built with Kotlin. And while the development tools for Kotlin itself are going to be free and open-source, the support for the enterprise development frameworks and tools will remain part of IntelliJ IDEA Ultimate, the commercial version of the IDE. And of course the framework support will be fully integrated with Kotlin.

-- https://blog.jetbrains.com/kotlin/2011/08/why-jetbrains-need...

This is less and less true as Java evolves. For example Java streams expect you to use Optionals to represent absence, which means they interoperate awkwardly with Kotlin which expects you to use Kotlin nullable types to represent absence. Another example: Kotlin has gone through multiple rounds of different ways of doing async, none of which is compatible with Java's new fiber implementation, so they'll either have to go through yet another incompatible rewrite of how they do async or be more incompatible with future Java libraries.

Subjectively, a lot of Kotlin features are implemented in a kind of ad-hoc way because they're designed to be as easy to use up-front as possible, at the cost of consistency. So the language has a kind of "technical debt" - it's hard to evolve it in the future. Add in the fact that the language lacks the higher-level abstraction facilities that would let you work around these incompatibilities (e.g. Scala has its own Option that's different from Java Optional - but this isn't a big problem because you can write a generic function that works on both. But you can't write a function Kotlin that works on both Java Optionals and Kotlin nullable types), and I'm really skeptical about its future.

Personally, I find Java's Optional to be kludgy and annoying to use.

An extension value clears this up in my Kotlin code, something like:

    val <T> Optional<T>.value: T? get() = orElse(null)
Allows you to do:

    repository
        .findByFoo(bar)
        .value
        ?.doSomething()
Slightly ugly, but allows you to gracefully unwrap Java Optional's into something Kotlin understands.

Regarding project loom and coroutines - I don't see why loom won't work in Kotlin codebases as-is. The change would be made in the corountines library, not user codebase.

> An extension value clears this up in my Kotlin code, something like:

You can convert at a boundary, which is fine if you have a line between Java and Kotlin parts of your codebase. But you can't seamlessly mix Java and Kotlin and use the same functions with both, which is what some Kotlin advocates try to claim.

> Regarding project loom and coroutines - I don't see why loom won't work in Kotlin codebases as-is. The change would be made in the corountines library, not user codebase.

I would bet they'll need incompatible changes, because there are subtle differences in the models. (Or they could keep the same API but with subtly different thread safety guarantees - but that would be a whole lot worse, breaking existing code in nondeterministic ways).

Programmers rarely have consensus on anything language-related, but their preferences are not always evenly distributed. Our decisions re Java aim to cater for the majority of professional teams, which may not necessarily be represented by the majority of commenters on HN. If you don't understand why many more teams prefer a language with choices that appeal to you less over languages with choices that appeal to you more, the answer may be that your preferences are not the same as those of the majority of teams.
This is the most infuriating kind of answer: There are concrete complaints and this comment addresses none of them. Claiming that there are people who prefer Java's syntax to be inconsistent isn't useful without saying why they do.
1. I don't agree the syntax is inconsistent at all. All Java type declarations are terminated with a `}`. Using a different terminator is inconsistent, and that's the thing that requires justification. For the time being, while records are still new, the justification of saving a single character was deemed insufficient. When it comes to inference, I also don't see an inconsistency. Inference infers types or type argument based on the available data. For example, in `var x = new ArrayList<>()` there is simply no information that can allow us to infer a type argument; on the other hand, if a method's return type is `List<String>`, `return new ArrayList<>()` can infer the argument.

2. Even if there were inconsistencies, and certainly when it comes the the concrete complaints, people not only disagree on what's a preferable feature (I, for one, strongly dislike extension methods -- and consider them an anti-feature with a negative overall contribution -- and much prefer default methods) but they also don't pick a language based on one feature or another but based on a gestalt of properties. The languages mentioned by the commenters make different tradeoffs that have significant downsides alongside their upsides (e.g. they don't match the evolution of the platform; they add implicitness that makes it harder for some to read code; they have a lot of features that need to be learned, each of which is pretty underpowered), and it seems that more people prefer the overall tradeoffs Java makes.

BTW, languages also have important meta-features. For example, every language needs to adapt over time, and the question is how it does so. The three languages that have managed to successfully support large programs that can evolve over time, maintained by changing teams -- C, Java, and to a lesser extent C++ -- have shown they take evolution seriously. They maintain compatibility and choose their features carefully (well, C++ maybe less so). Kotlin has lots of features, but it already has more outdated large features than Java because it adds features to address a certain problem and then the platform addresses them in an altogether different way (data classes, async functions), and as a result it's showing its age quicker, too. Java has proven that it evolves well, and many think it evolves better than most other languages.

> Some inconsistency of choices also kinda baffles me. First they added support for skipping necessity of mentioning generic type inside <> during instantiation, only to introduce local vars later that require you to mention generic types within the same <>.

I just came across this as a potential footgun the other day. I had a var list = new ArrayList<>(), then later added a bunch of Foo's into the list, and then when I called an overloaded method with the signatures log(Object obj) and log(List<Foo> fooList), it was calling the Object version. I would think some better type inference should be possible there, but if not, making programmers declare the type(s) at least once is a necessary constraint.

Why don’t just write var list = new ArrayList<Foo>()? The point of inference inside <> has always been to save you from repeating yourself from copying from the left to the right, which is a non-issue when you are saved from specifying it on the left.
Completely agree, but it did surprise me a bit and I didn't find much when I googled around for "don't mix var and the diamond operator."
(comment deleted)
The Java team is very conservative in building out new language features- they find the things that have been battle tested in the wider language space, and take their lessons and adapt them into Java features. IMO this is a good thing. If it's "stealing" then every other language is "stealing" from each other, too.
Java, the Debian of programming languages. I guess that would make Scala like Arch and Haskell - Gentoo?
It's a pity they never stole quotemata() from Perl instead of having to escape regex metacharacters.
(comment deleted)
> Honest question - isn't Java just trying to "steal" Scala's concepts and catch up to the "cool" languages?

Is that somehow bad thing?

(comment deleted)
We are all taking stuff that ML had 40 years ago, or maybe Lisp 50 years ago. I wish the debates around language features could just get past the idea that language X is stealing from my favourite language Y.
As an industry we have amnesia. Many developers, including programming language designers, are simply unaware of what was done decades ago and thus end up reinventing the wheel.

Before jumping into writing new code we should develop the discipline to start by researching what has been done before in similar domains. Even if the old code isn't reusable we can often apply the same design patterns or at least avoid making the same mistakes.

Sure, but I think you forget: we aren't the first industry to have amnesia.
It is just simply too hard to read several hundred papers and do bin-surfing to find out what was done in the historical past of computing and grab the timeless ideas.

We need government/grant supported researchers and tech writers who can do this work and create a curated, focused bunch of books describing the best methods and designs. I found the Architecture of Open Source Apps to be amazing, but we need something regularly maintained for all software domains.

In that case you need to look at the people designing java/C# in the 90s.
Meh. Take pattern matching for example... that dates back at least to the SNOBOL[1] days. So you could say that every language that has first class patterns and pattern matching is "stealing" from SNOBOL. Or probably SNOBOL "stole" the idea from some predecessor. My point is, "imitation is the sincerest form of flattery." Languages have been "borrowing" ideas from each other dating back to the beginning of programming languages. There's nothing particularly notable about Java continuing that tradition.

[1]: https://en.wikipedia.org/wiki/SNOBOL

Java's stated goal has always to be conservative with adding new features, to implement what the "cool" languages are doing after it's been battle tested. It's been this way since the start.
I was just reading the final chapter of The Well-Grounded Java Developer, and it quotes thus on the borrowing of ideas, which is apt to mention here:

One of the surest of tests is the way in which a poet borrows. Immature poets imitate; mature poets steal; bad poets deface what they take, and good poets make it into something better, or at least something different.

—T. S. Eliot

Scala is not cool in any way, shape or form. It’s an unsuccessful, niche language, that has implemented probably every possible feature ever done in a programming language, including some really backwards ones (like putting XML in the middle of your code). Having all those features makes Scala harder to learn and understand. Programming language features aren’t “stolen”, since they aren’t really “owned” by any given language.
You're getting down voted but your comment is basically correct. Scala contains some good ideas but due to high complexity and weak tooling support it has failed to gain mainstream adoption. And it's widely recognized now that embedding XML literals in the code was a bad idea; if we want to do something like that then it should be a more generalized mechanism that could support other hierarchical data formats such as YAML or JSON instead of being locked in to XML.

Despite its flaws, Scala isn't a bad language necessarily. It will still continue to see niche use. But it no longer seems like the obvious path forward for general purpose application coding.

I don’t think a generalized mechanism that would simultaneously suport XML and JSON would work, because they have different structures, uses, and generation/parsing mechanisms (XML/HTML is often generated using textual templates, but JSON is generated and parsing by going by plain old objects.

While Scala is perhaps not a “bad language”, it contains many flaws and I don’t see much of a bright future for it. (Also, Scala 3 brings new single-use features, and an entire alternate Python-style syntax, because learning one syntax is apparently not enough.)

My point was that XML and JSON (and YAML and S-expressions) are fundamentally similar in that they can be modeled as tree structures. So, in principle it might be possible for a programming language to have generalized support for tree structured data literals which could then be encoded into multiple different external formats. As to how that could work syntactically without turning into a huge mess, I'm not sure.
The only company I've ever known to use Scala in a big way, based on their job ads, is Disney Streaming. Now their streaming service is successful and stable, so it clearly was the right choice for them, but honestly I can't help but think they chose the runt of the litter. I imagine it's a developer who wanted the latest fad functional language on their CV many years ago, abandoned the company (or got promoted out of the dept.), and now Disney's current developers have to support a language that is mostly not idiomatic with the OOP libraries it uses, and lacks the userbase and support other languages enjoy.
Honestly I've used Scala in production in 3 separate companies and ten years ago everyone realized that XML in the code was a terrible idea. No one serious does it.

I'm working in Java now, but I thought Scala was fantastic. The problem was that it attracted functional programming puritans and the category theory astronauts -- both groups had some really good ideas -- but pragmatism is at odds with elegance and focusing on delivering business value versus developing knowledge of theory can be a tough balancing act.

Yes, around the same time Scala was really big in the London financial sector with Morgan Stanley championing the language. The Guardian's back-end also runs mainly on Scala. There were also monthly Hack The Tower all-day Saturday meetups for Scala and Clojure and the turnout for Scala was much higher than for Clojure though both had a decent crowd. The scene is lot less colourful since these days. All we have is Node and Python meetups, ie. boring stodge.
As a Scala user, every other language out there is still a painful step back. Kotlin or Typescript or even Rust are painful once you're used to having HKT and real monads. And while Haskell-the-language is good, if you think Scala tooling is bad....

I predict Scala will see an upswing for the same reason that OCaml has been on an upward trend in recent years; even if a language is no longer unhyped, if it's well-designed then it still ends up being the best way to get things done.

(The XML thing is a ten-years-out-of-date talking point, FTR)

I predict the opposite and for the very reason you inadvertently suggested. The more Scala devotees obsess about HKT and dream of Haskell in their sleep the less relevant to business Scala will remain.
HKT is the means, solving cross-cutting business concerns without fragile hacks (like reflection or metaclasses) is the end. If you use a language without HKT, you will have those flaky hacks in your codebase (because the alternatives are worse), you will have outages because of them, and your business will suffer (admittedly maybe not by enough to matter, depending what business you're in). Think back on your last outage - it's a good bet that using Scala would've prevented it.
If that was the case dynamic languages would be non-starters. Believe it or not there are a lot of businesses, some quite large, which have been chugging along quite nicely on PHP or Ruby for over a decade. HKTs may be fun to play with but let's get them in perspective as nice-to-haves.
> Believe it or not there are a lot of businesses, some quite large, which have been chugging along quite nicely on PHP or Ruby for over a decade.

Sure, and they either follow extraordinary development practices, or they have outages basically all the time (e.g. the famous Twitter "fail whale"). Like I said, in some lines of work (probably far more than people on HN would like to think, frankly) you can get away with that.

The XML thing is still supported by the language, even if you need to install a separate first-party package to make use of it, so it is not an out-of-date talking point. There are other issues, such as the undebuggable macro system that has too much power, the insanely overloaded `implicit` keyword (fixed in Scala 3), or the two competing syntaxes introduced by Scala 3.
Then can you explain why Scala's spec is so small? Even Java's spec is much larger.

I'll tell you the answer: because the language is comparably well designed, with a lot of foresight, and the fundamental features work well together. Also you are totally right about XML. This was a total mistake and in fact already has been removed from the language - I think a few years ago.

Maybe you still have the old Scala in your head? That would explain your post a bit I guess.

> Programming language features aren’t “stolen”, since they aren’t really “owned” by any given language

I agree with that though and I think it's great that Java is progressing. There is no shame in copying the good things.

Part of the reason that Scala's spec is so small that so many features are incredibly generic. Concepts like implicit are overloaded in a bunch of different ways and give rise to powerful but complex patterns that you need to understand to use the language, even if they're not strictly required for it. And since all of these different features and patterns are optional, you end up with every Scala codebase using a slightly different subset of the language, and different communities evolving very different ways of doing things. Look at Spark code vs. ZIO code and it's like night and day in a lot of ways.

Scala 3 improved the situation a bit by breaking the "implicit" concept down into a few discrete concepts, but the language is still incredibly expansive, despite the "look how few keywords we have" talking point.

Honestly, I do think that modern Scala is very well designed. But unfortunately the ecosystem and tooling and corporate support for it never really got to the point where it feels like a practical choice for most teams.

ZIO and other purist FP code bases are probably not the most common, but definitely not the most well loved aspect of Scala — pragmatic FP would be that, that uses local mutability when that is readable, but prefers an immutable public API.
I think ZIO is really a very pragmatic appraoch to FP, similar to Monix (which is a bit less comprehensive).
> Then can you explain why Scala's spec is so small? Even Java's spec is much larger.

Are the two specs comparable? Looking at the Scala 2.13 [0] (I can’t find a Scala 3 spec) and Java 19 [1] specs, while the Java spec is much longer page-wise, it is also much more formal and detailed:

* The Java spec sometimes defines things that might count as part of the standard library (eg. how threading and wait/notify work).

* The Scala specs just says “Scala source code consists of Unicode text.”, but the Java specification says what Unicode is, and talks about UCS-2/UTF-16 and why chars have surrogates (over almost two pages).

* The Java specification also talks a lot about the JVM and bytecode. The Scala spec does not include any details or assumptions about the underlying execution environment.

* Scala also delegates a lot of things that you would consider part of the language (e.g. the + operator for integers) to the standard library. Also, how do I figure out how large an Int can be in Scala without reading stdlib docs or writing a program to query Int.MaxSize?

* Similarly, comparing the keyword count of Java and Scala doesn’t necessarily yield sensible results, since Java considers `int` to be a keyword, but in Scala, this is just the name of a standard library class.

Also, the size of the language specification has nothing to do with how easy a feature is to grasp. Implicits may take 8 pages in the specification, but they are difficult to understand and tricky, especially if the implicit keyword meant 4 semi-related things in Scala 2.

---

> Maybe you still have the old Scala in your head? That would explain your post a bit I guess.

Which “old” Scala? Scala 3 still has ~all the features of Scala 2. It also has two separate syntaxes, a Java-like and a Python-like syntax, to add even more confusion and even more things to learn.

> This was a total mistake and in fact already has been removed from the language - I think a few years ago.

From the Scala 3 docs [2]:

> XML Literals are still supported, but will be dropped in the near future, to be replaced with XML string interpolation[.]

[0] https://scala-lang.org/files/archive/spec/2.13/spec.pdf

[1] https://docs.oracle.com/javase/specs/jls/se19/jls19.pdf

[2] https://docs.scala-lang.org/scala3/reference/dropped-feature...

For the operator thing, isn't that just because there is no difference between an operator and a method in Scala?
Pretty much, yes. Operators being methods of stdlib classes and being a guest language on the JVM are two things that let the spec be shorter by omitting details a developer needs to know.
I suppose I've always seen the audience for the spec as language implementors, not users, who are unlikely to look at it.
You make some valid points. I still think after removing the points you mentioned, Scala's spec will still be shorter - but I'm too lazy to do that.

And reasons are for example that the language just has less exceptions. Like the + "operator" which is just a method. And Int just being a datatype - no need to put this in the spec. Or that "int" is not a keyword in Scala - well, I think that is totally a good thing and also comparable, why not?

> Also, the size of the language specification has nothing to do with how easy a feature is to grasp

Sure, but your original claim wasn't just "it's hard to learn Scala" because with that claim I would agree.

> Scala 3 still has ~all the features of Scala 2

Scala 3 has removed a lot of features. In particular powerful features like Scala 2's macros. So what you say is just wrong (the tilde in front of the all really doesn't make it better).

> It also has two separate syntaxes, a Java-like and a Python-like syntax, to add even more confusion and even more things to learn.

That's a valid point, but if this is your level of complaint, then you must hate Java much more than Scala. It has way more warts and confusions than Scala. I know both languages in and out.

> > XML Literals are still supported, but will be dropped in the near future, to be replaced with XML string interpolation[.]

Careful here. XML literals are still supported (even though deprecated), but that is not xml support. XML support has been completely removed from the compiler and is now in a library that needs to be imported. This is different from before, where XML was really built into the language.

In other words: try to use XML without that library and it will simply not compile.

> Scala 3 has removed a lot of features. In particular powerful features like Scala 2's macros. So what you say is just wrong (the tilde in front of the all really doesn't make it better).

Sure, macros were removed, but they were an experimental thing in Scala 2 (and another case of language bloat IMO). If you look at features used in day-to-day programming (in [0] or [1]), the list of removed features is quite short, and many of them are very minor things that can be usually automatically replaced, and some of them were still supported in Scala 3.0 (perhaps with a compatibility flag).

[0] https://docs.scala-lang.org/scala3/guides/migration/incompat... [1] https://docs.scala-lang.org/scala3/reference/dropped-feature...

Cool, now we are from

> Scala 3 still has ~all the features of Scala 2

to "Scala 3 has most of the day-to-day (from a language-user's point of view) programming features". I'm fine with that. :)

> Which “old” Scala? Scala 3 still has ~all the features of Scala 2.

You linked to a page that has several actual dropped features from Scala 3. If Scala 3 didn’t drop features, it would still be Scala 2. What exactly is the point of all this edgelordery? We get it, you think Scala is uncool, but that’s just like your opinion man. Did you really jump onto a comment about Scala just to shit on Scala? I’m horrified to think of using a language that someone like you might actually think is cool.

The list of dropped features isn’t very long, and many of them are very minor or niche things. Nothing comparable to Python 2 → 3, for example.

I started by commenting on the OP’s statement calling Scala “cool” and talking about the feature bloat in Scala (that makes it uncool and hard to learn).

Ironically, that XML(ish)-in-code idea did survive in JavaScript, where embedding HTML in code with things like JSX is now pretty standard. But that's the rare case where a programming language is so deeply entwined with a markup language that it's natural to bring them together. XML proper is increasingly rare as a data format nowadays, so Scala's support for it feels like a strange relic of a bygone era.
It's a pity its adoption is stagnant. But it was highly successful in at least two respects:

* introducing Java developers to the world of FP about ten years ago (i.e. before JDK8 and Kotlin) with a lot of that knowledge transferable to Kotlin in particular

* significantly influencing Kotlin and evolution of Java itself

Don't forget that it also made Spark (and to a lesser degree Flink and Kafka) possible.

Spark is still not compatible with Scala 3.2 unless you want to burn in dependency hell.
My honest reply to that would be, do some more java and see for yourself. Your last experience with java was Java 5, which is ... ancient.

Java has gone through a lot of changes, and is actually a very nice, streamlined language now.

You'll probably be very surprised to hear it even comes with a jshell and jwebserver these days!

I would not call Java streamlined by any measure, API size, library size, or LOCs. If you want to see a streamlined API, see Typescript + Webpack which will trump in all of those metrics.

Source: Me, Java coding professionally since Java 1.0 when it was "streamlined" in 1997, and Typescript for the last 5 years.

That doesn’t seem like much of a source. Do you have specific examples?
Try compiling a program that prints Hello World to the console and see how many bytes it takes in both source and shipped form. JS/TS will indeed win every time in those metrics.
Why is that a metric that matters?
Download latency is important in many contexts.
But isn’t important in the hello world context and in other contexts I don’t think it’s a great comparison.

Typical node apps will ship with megabytes of extra files for functionality that would be present in the Java standard library. Even if I take your claim as fact, programming languages are about trade offs. While Java might suffer from download latency it will more than likely beat TS on execution time and gc latencies.

But recall that Java was once pushed heavily in the form of applets, where code size and download time are critical. That's why Sun developed pack200.
This is 2023 not 1996. Applets have been deprecated for a long time.
You asked for specific examples of where these metrics matter, the web is clearly a specific example.
It isn't. It tells you nothing about how the language scales up, only how simple it can get when you want to print a value.

https://rosettacode.org/wiki/Hello_world/Text

You can see that some languages are simpler than others (even JS can be beat by this useless metric, check out APL). But it gives you no idea how the language scales up for complex tasks.

An Hello World in java is a single class file of a few hundred bytes so I am not sure that is the right example. Source code is more verbose, and although I do prefer Typescript I don't find it a tragic issue.

In both cases for anything more complex you will end up with a truckload of libraries, so even there there isn't much difference.

I think that were Java is not streamlined at all is in memory usage, because you will probably be able to get the same result with a fraction of memory in Javascript (and many other languages). I'm not sure if the problem is more on the JVM (heavyweight objects and no value types?) or the libraries, I suspect both.

> I'm not sure if the problem is more on the JVM (heavyweight objects and no value types?)

Value types are being worked on with project Valhalla, but also the VM doesn’t give memory back to the OS. It holds on to it up until -Xmx, which by default if i recall correctly is 25% of the machine, so it’s hard to really know how much your program is actually using. It’s actually one of my biggest gripes about the JVM.

Obviously it does. I said that typically it will expand the heap until Xmx is reached, which according to your links is exactly what G1 will do.
Javascript is quite hungry for memory as well, but that’s simply the way of performant tracing GCs - the bigger space overhead they have, the less work they have to do.
Is that really what you feel is a useful metric for a programming language?
I'm sorry if 25 years of experience in Java programming doesn't seem a lot to you. Given it's almost as long as Java has been about, and I've worked at EA and other companies full time as a mobile server side architect, am an open source contributor (albeit not a popular contributor, but one who codes in 4 languages regularly) perhaps you might like to reconsider my experience as sufficient.

Java has a lot of required infrastructure, typically Spring these days, which brings with it all the boiler plate. Spring Boot is an "opinionated stack" (Google it) which basically is needed because _there is so much configuration required_ due to its enterprise level design, you can't just strip Spring out and have Java serve a basic 200 RESTful endpoint in the same footprint as other modern languages.

Additionally most projects typically include a lot of legacy mis-steps or third party Apache libs that have added bloat (3-4 logging libraries in a single project not uncommon, 2-3 Date apis, numerous XML or JSON parsers etc etc). So while code on the surface seem compact, in actual fact it's built on bloat. And my God the stupid FactoryFactoryFactory antipattern and similar over-engineered crap (I'm ashamed of the neckbeards of my age that actually thought this was a good idea).

In contrast TS (or JS), for server side do not require boilerplate, and the syntax lends itself to near native JSON handling removing the need for heavyweight parsing of RESTful or GraphQL endpoint arguments and responses. Then there's Serverless... Java cold starts in themselves are still a joke, Java is clearly better when it comes to batch work and warmed up, but need a quick small AWS Lambda to do something, a true one purpose "microservice" and TS will be both shorter to write and quicker to start, moreover it's half the cost owing to memory and CPU overhead (there are cloud metrics out there to prove this) but Java is more performant and we're talking about streamlining here so I've gone off topic.

If you're a Java fanboy, like I once was, you'd do well to spend some time in other languages, not just to play in some small projects, then you'll come back to Java with a different perspective.

FWIW I wasn’t personally attacking you. I was just trying to make sure you provide evidence of something being bad when you claim it to be bad. That being said I think your experience isn’t representative of the ecosystem today.

Spring is not Java. It is not a required dependency. In the last 10 years I haven’t worked on a single Spring application. There are plenty of alternatives with modern apis: Play, Quarkus, Micronaut, Helidon, Javalin etc.

> Additionally most projects typically include a lot of legacy mis-steps or third party Apache libs that have added bloat (3-4 logging libraries in a single project not uncommon, 2-3 Date apis, numerous XML or JSON parsers etc etc).

Left pad, right pad, isNumber, isArray?

I’ll give you serverless, but I’ll repeat what I said in other comments: languages are about trade offs and use cases. They don’t have to be the one language to rule them all.

Some clunky frameworks are written in Java therefore the language is bad. Great argument
> Spring Boot is an "opinionated stack" (Google it) which basically is needed because _there is so much configuration required_ due to its enterprise level design

And more often than not you do want to have a whole toolbox available. How long will it take for you to add X to your TS microservice? Finding a dependency that looks somewhat stable (which will already bring in half of npm packages) is already hard enough, and my experience has never been too great with the JS ecosystem. It has a few gems among a trillion low-quality, always breaking shit.

Also, most newer project definitely don’t bring in datelibs, as the java.time package is very great (and was actually “brought into” the standard lib from a popular library, which is how it should be).

That overengineered bullshit actually comes from C++ of the time, it just probably didn’t segfault in java and thus higher levels of abstractions could have been achieved in the latter, sticking the concept to java, but I fail to see again, how it has any relevance.

Come on, JSON parsing is like one library - that not being available as is is not a problem at all..

Re: serverless. Honestly, is it really as popular a deployment method as I see it mentioned all around? Like, I can’t imagine a serious web app using it for anything besides converting images, videoes/etc, any you ain’t gonna use TS for that either. Coldstart still matters, but it is way overhyped.

So.. how exactly TS is better? If you claim to “spend some time in other languages” at least mention something on the language side that would somehow cause a difference. TS is not a paradigm-changing language at all..

I love the coding Java in C++ critic, when what Java designers did was adapt Objective-C semantics to the most common C++ programming patterns pre-1996, in a safer package, and GoF book used Smalltalk and C++, published about two years before Java came to be.

While, Java EE is a pivot from Objective-C framework, from the collaboration between NeXT and Sun, Distributed Objects Everywhere.

It is like people don't get history of programming languages.

I'm Java fanboy, but I look at other languages. Python is nice, Scala is great. But JS (and TS as a result) are amalgamation of different features pushed together by different browser vendors. The resulting code is unreadable gibberish, and support in any IDE is almost non-existent because of the dynamic nature of that language (similar to python) and finding usages almost always needs to be done using string search.

I would understand any other language to be better than Java, but Javascript is in same line as PHP of bad.

(comment deleted)
I don't consider SAMs as substitutes for real lambdas to be progress. Kludge would be more accurate.
Yes, and that's a fantastic strategy.

Steal the bits that work, don't steal the bits that don't work, get cooler but slowly without adding a bunch of useless rough bits along the way.

It is called Java Virtual Machine, not Scala Virtual Machine.

The guest languages are just that, guests that eventually leave the party.

Comparing ten-years-ago Java with todays: Yeah, it’s come a long way but it’s nowhere close to what Scala is (for better or worse; I truly don’t know).
i wrote scala almost exclusively for 10 years and last year started doing more java. are there things i miss from scala? yes. self types. for comprehension. better list and collection syntax. scalas collection processing is probably the best there is.

are there things i don’t miss? yes. implicit. execution context on every future method. slow compiles. sbt

i couldn’t do java without records and “var”.

i don’t think scala has a real future. the binary incompatibility crushed scala for so long. sure scala 3 fixes it but not much has moved to 3. java is iterating at a faster pace than scala. they aren’t the same. scala was designed to be more terse and flexible and always will be.

but i don’t think that has made my programs worse in java. in some ways the lack of flexibility makes the code more predictable and easier to maintain

Call me around the year 3004 when they add unix datagram sockets, fork(), and native support for syslog… so that one can implement sane server software.
Unix sockets were released in java 16 officially though it was always supported before that in third party software.

C style fork() seems insane for any gc-type languages, so ?? Threading in Java post virtual threads has been so pleasant that I'm like why would one bother?

The vast majority of applications use third party logging and many have the ability to call out to syslogd.

I'm not entirely interested that every language fits perfectly into the UNIX classical "everything's a process / pipe" style model.

> Unix sockets were released in java 16 officially though it was always supported before that in third party software.

I said datagram, not stream.

> C style fork() seems insane for any gc-type languages, so ??

java daemons have no way to signal systemd their readiness. The unix way is to fork and exit. The systemd specific way is to use dbus to tell systemd that the process is ready.

java supports none of that natively. So if you have a service that depends on a java daemon, you can't sort them properly.

The normal way is to hack the java daemon to be launched from a bash script, that will test if it's ready using curl or netcat, and will in turn tell systemd about it.

As it is, doing a sane daemon in java is impossible without having some JNI fun.

> I'm not entirely interested that every language fits perfectly into the UNIX classical "everything's a process / pipe" style model.

Ok, how do you propose to tell systemd that your daemon is ready to accept connections?

> As it is, doing a sane daemon in java is impossible without having some JNI fun

And there is a brand new Foreign Memory, Function API in Java (from project panama), which makes it quite possible and ergonomic.

You can use Type=dbus with pure java dbus client. Or just execute systemd-notify
Ah i didn't know about systemd-notify as a binary!

I don't want to use dbus as that'd be an extra external dependency.

Equivalent of syslog() is still a problem without using external dependencies.

None of that is required for Cloud development, yet another one that missed the irrelevancy of POSIX in modern software development.
Ah, so you don't use systemd?

Just because you don't know about something and never learnt how to use it, it doesn't make it irrelevant.

Chances are it's a Kubernetes pod using containers these days :)
Yes with a /dev/log unix datagram socket mounted from the host and forwarded to a log collector that java can't connect to, so instead stdout is redirected but it doesn't support log levels.
Better go tell that to Amazon, Google and Azure.
Unsurprisingly, it seems after all people do logging with syslog (as if there was any doubt) https://www.ibm.com/cloud/blog/kubernetes-log-forwarding-sys...
Not much experience with IBM Cloud it seems, dumping a random blog post from 2017, here you go how we actually do it in modern times,

https://cloud.ibm.com/docs/log-analysis?topic=log-analysis-l...

Did you even read the link you sent me?

That thing monitors journald.

Systemd is obsolete… let's use systemd!

Embarrassing :)

I do my dear, time to move forward from PDP-11.
A word of advice: read your links before you send them next time; it could make you look smarter.
No I don't, because hardly anyone still deploys barebones VMs, unless they can't do otherwise.

In theory, containers, application containers, and serverless language runtimes only need a type 1 hypervisor or bare bones kernel to execute.

In practice, there is still some kind of kernel underneath as convenience to the infrastructure people.

Actually, when we deploy VMs, it is mostly Windows ones, as Windows containers still have a couple of gotchas, so no systemd there as well any way.

Finally, systemd is a Linux thing, and there are more UNIXes to choose from.

> Actually, when we deploy VMs, it is mostly Windows ones, as Windows containers still have a couple of gotchas, so no systemd there as well any way.

Ah you're a windows developer… Perhaps talk to someone who works on servers before completely dismissing valid input that is completely outside of your expertise next time?

> Finally, systemd is a Linux thing, and there are more UNIXes to choose from.

And all of those report readiness with a fork(), which java can't do.

> Ah you're a windows developer… Perhaps talk to someone who works on servers before completely dismissing valid input that is completely outside of your expertise next time?

Nope, I am a Java, .NET, nodejs and C++ developer.

Cross platform languages.

> And all of those report readiness with a fork(), which java can't do.

fork() is legacy, it can't even handle modern UNIX workloads with threads.

> Cross platform languages.

You don't know unix things, yes. I can't understand how can someone be so proud of not knowing something.

Python and C++ are cross platforms and both support the things I listed that java doesn't support.

> fork() is legacy, it can't even handle modern UNIX workloads with threads.

Lol, ok. Next you're going to tell me file descriptors are obsolete?

Just a curiosity, what do you use instead of fork()?

My dear HN newbie, I have used more UNIXes in my life that you probably know about.

Some education for you about fork(),

https://dl.acm.org/doi/10.1145/3317550.3321435

https://thorstenball.com/blog/2014/10/13/why-threads-cant-fo...

> My dear HN newbie

A person can live for decades before creating an HN account.

> I have used more UNIXes in my life that you probably know about.

I've used 5 different unix kernels. I've even read manpages instead of taking pride in not reading documentation, like some HN users with a large ego.

> Some education for you about fork(),

I'm perfectly aware of the issues of fork() when threading is in use. There are a lot of issues to keep track of when using threads. One more, doesn't really make much difference.

How do you do this? https://man7.org/linux/man-pages/man3/daemon.3.html

Do you plan on replying to my question? What do you use instead of fork()?

UNIX is irrelevant on the cloud, unless one is stuck deploying legacy workloads on VMs, this is what we use in modern applications not stuck in the past.

https://aws.amazon.com/eks/

https://azure.microsoft.com/en-us/products/kubernetes-servic...

https://cloud.google.com/kubernetes-engine/

https://cloud.google.com/appengine

https://azure.microsoft.com/en-us/products/app-service

https://aws.amazon.com/lambda/

https://azure.microsoft.com/en-us/products/functions/

https://cloud.google.com/serverless

If you insist in calling fork() as matter of existial crysis, by all means do, Java doesn't stand in your way, learn JNI.

https://github.com/luben/process-jni/blob/master/src/main/ja...

> UNIX is irrelevant on the cloud

On what exactly do you think the containers run on?

What kind of system call do you think happens on a machine to create a new container?

Again, you're so proud of not knowing something. The fact that you write very high level code and have other engineers figure out how to run that code for you, doesn't mean that their job is unimportant.

In fact, it might be the case that they might replace you, but not viceversa :)

Type 1 hypervisors, which don't need UNIX at all, like on Azure.

I feel it is you that don't have a clue about how Cloud infrastructure works.

It seems like your job is so high level you lost track of the fact that virtual machines run on actual machines :)
Structured concurrency sounds amazing, but it will probably take some time till it is widely usable :(
Foreign Memory API can't come soon enough. The weird hoops you have to jump through to allocate large buffers of memory in Java are perhaps my least favorite aspect of the language right now.
What I’d really love to do is limit memory by Java thread, rather than per process. Allowing things like job runners to not crowd out others.
It's been a while since I've programmed in Java. I wonder how good the concurrency stuff is these days. On a somewhat related note I was talking to a team from a random bay area company on how they switched from Java/Spring to Node and that Node is slower but since it's single threaded they load balance a bunch of servers and in practice it's just as fast when considering the developer productivity.

Compute is really cheap these days, so I wonder how much it's worth it to squeeze every drop of performance out now.

Compute is cheap if you're doing trivial things that doesn't require much compute.

Flip side is that this is true for everyone. If you're only doing trivial things that could have been done 20 years ago, you really don't have much competitive advantage. It's difficult to be competitive in the area of solving easy problems.

> Compute is cheap if you're doing trivial things that doesn't require much compute.

A lot of the work on the web/API side is I/O bound (e.g. waiting for network I/O to database) so unless throughput is your game (e.g. Stackoverflow), it seems that Node is "good enough" for most web/API work.

It is I/O bound because you aren't using the available compute as much as you could.

Modern hardware is insanely powerful. Like it's absolutely bonkers how much you can do on a modern computer. Although most modern applications have capabilities on par with a 2006 flash game.

All true, but there's a point of nuance: because cloud is all virtualized, you are taking advantage of the underlying high performance modern hardware because a serverless Node function is one of who know how many on the physical hardware.
The vast, vast majority of "business code" even at startups and unicorns like AirBNB and Uber is not doing "compute-bound" things. They're all basically fancy CRUD apps.
Yeah, you can do more though, is my point. The CRUD market is pretty crowded.

Feels like a lot of the AI hype is the sudden discovery that modern computers are actually pretty fast and squandered doing book-keeping in small-to-medium SQL tables (not that you need LLMs to do interesting things with them).

Basically anything that required a data center in the year 2000 you can do on a powerful desktop PC today.

Yes, back in 2004 DHH created Rails on an 800Mhz PPC iBook with 256Mb RAM and launched Basecamp for the first year on a server with the same amount of RAM. A bargain basement VPS comes with 4 times the RAM these days.
Uber - are you kidding? Their shortest route algorithms are extremely CPU-intensive.
Compute is cheap if you only run one program on your computer. The moment two or more "compute is cheap" programs run on a computer is the moment when cheap is not so cheap anymore.

Nothing like IntelliJ crashing during a video conference and then indexing your entire project from scratch... Encoding video in real time is CPU intensive, indexing a hundred libraries adds oil into the fire.

> Compute is really cheap these days, so I wonder how much it's worth it to squeeze every drop of performance out now.

And that's why every single Electron app is slower on a modern 4.7 GHz 8 core CPU than a (although not as pretty) native app on a single core CPU in 1999. Spotify is slow as molasses and has less features than foobar2000, MS Teams is slower than any messenger I used in 2005, and all those Postman-like apps are just a horror to use compared to a simple bash script with wget.

Case in point: I cannot use MS Teams on my state of the art computer when I'm compiling. It's just so slow to type and switch chats.

> and all those Postman-like apps are just a horror to use compared to a simple bash script with wget.

Personally I like having collections of requests, automatic formatting of responses, dedicated fields to enter headers into, automatic parsing of cURL / HAR etc, the ability to generate code in various languages...

There's a lot more to most of these Postman-like apps than just making requests!

Though I have seen Insomnia just completely choke up on large responses (10s of MBs) that Sublime renders in a flash - so you're not completely wrong, just throwing the baby out with the bathwater :)

> I wonder how good the concurrency stuff is these days.

What were you missing? Java had threading, task, threadpool capabilities for ages. It comes with all kinds of concurrent collection classes and running something in parallel could be just one .parallelStream() away. There are also countless reactive frameworks that minimize thread count. Java Loom / green threads are available since Java 19 (hidden behind a flag).

Sorry, I meant in terms of developer ergonomics and ease of use, not purely compute performance.
The Reactive java frameworks are way more developer ergonomic than NodeJS if you use the virtual threads previews, otherwise you have to use callbacks/futures. But at least you have runtime type checking...

Vertx is way better than Node in a lot of ways, and faster, and easier to debug. Lock the event loop? You immediately get a log that you did something bad.

Like I just got an error in my IDE with TypeScript "ChartConfiguration is not generic". So I cmd+click into the type definition and it's a ChartConfiguration<T>. okay...

The whole ecosystem feels super fragile. It hurts productivity and moral. This just doesn't happen with Java.

Genuine question, why developer productivity was higher in node?
Node is much simpler to work with, and if you're running one shot, short serverless ops (i.e. not batch), faster to start (no JVM cold start) and cheaper to run (less RAM) than Java.

If they're really concerned about performance they'd not go wrong by using Deno which often has at least double the performance of Node https://medium.com/deno-the-complete-reference/node-js-vs-de...

Deno for a lot of operations is actually comparable to Java level performance: https://programming-language-benchmarks.vercel.app/java-vs-t...

Of course there is cold start. Both Node and Deno use JIT compilation just like regular Java, which means they warm up. JS code will use more RAM than Java for equivalent constructs, not less. You may be fooled though, by the way that the JVM by default will use free RAM rather than burn energy/CPU collecting garbage when it doesn't need to. So it will look like your app is using a lot of RAM but in reality the JVM will give it up when asked.
My experience of paying for cloud services does not back that up.

Java AWS Lambdas are typically 2-3x heavier in memory usage than a TS/JS equivalent, and the benefit of that warmup is negated if the Lambda shuts down due to idle time.

"Give it up when asked" !== less streamlined, it means expanding heap is required for normal operation. Too little heap, it buckles, GC is almost constant, and performance goes out of the window.

That's inherent to any GC algorithm. More CPU time = less RAM usage because garbage is collected more aggressively. I don't understand why you think that JS, a JIT compiled GC'd language, doesn't warm up and doesn't have to trade off GC time vs memory.
Bun is supposed to be even faster.
> Node is slower but since it's single threaded they load balance a bunch of servers and in practice it's just as fast when considering the developer productivity

This sentence doesn't make any sense. It can't be both slower and just as fast, developer productivity is a totally different concept to performance. And being single threaded just means you have to spend more RAM to saturate your CPUs (threads are cheaper than processes), nothing stops you running many single threaded JVMs and load balancing across them, it's just inefficient.

> just as fast when considering the developer productivity

I wouldn't use Javascript and developer productivity in the same sentence.

The only reason why I am looking at Golang is because of its fast startup and low memory usage. I prefer the Java ecosystem and Kotlin specifically; how is the JVM's progress in this area for serverless, etc?
How is the generics story going in golang? I wonder if it brought a major paradigm shift in the way Go is written.
It is definitely better than before, but doesn't really change the game much. It has severe limitations.

My biggest hope when generics were announced was that we'd finally get an alternative to writing `if err != nil` 10+ times per function, but it doesn't support generic method type parameters. That alone kneecaps it severely by making type-safe method chaining useless in most scenarios (unless you never need to map to another type, ever, I guess. Lucky you.)

It's pretty rare you need to write anything generic unless you're writing a library, or library like functionality.
I don't know about a paradigm shift, but the craziest use of them I've seen is https://github.com/jhbrown-veradept/gophercon22-parser-combi... .

I watched the talk, thought I understood it "enough", then completely fell on my face trying to write a JSON parser.

Could be me though, maybe I should try it again now that it's been a few months

Not good.

Java needs set of microservice libraries reimagined from the ground up. Optimized for size and RAM consumption. Optimized for GraalVM compilation (it's bad, but it's not that bad, libraries make it that bad). Also preferably including new tool for building because Maven and Gradle are bad.

I'm in the same boat. I love Java, but I hate Java ecosystem. I hate golang, but I love its ecosystem. And I think that it's possible to write golang-like ecosystem for Java. After all there're people who wrote deno and bun to oppose node.js. Hopefully vaja will appear.

That's what libraries like Quarkus, Helidon etc are.
> Java needs set of microservice libraries reimagined from the ground up

Which has pretty much already happened.

Maven and Gradle are not bad at all, hell, Gradle is probably one of the few build tools that can actually handle more complex tasks correctly. Sure, that fancy new build tool definitely is more ergonomic to use for that hello world with 3 dependencies listed, but can it actually be used for generating locale files and whatnot? Not everything is running the compiler.

Java’s ecosystem is one of the best and I can claim that quite objectively.

Golang is many times well better designed than Java ever will be. Java has fundamental issues with the language (which is the reason Groovy and Kotlin exist in the first place).

If you want performance, stick with Golang. If you want rapid prototyping/dev, go with Python, 3.11 is much better in performance than older versions.

Yeah, their design of enumerations is tip top.
Go has it's own fundamental problems. Something very basic that turns me off is what happens to the original slice when appending to a it (done by calling append(slice, item) and using the result). Does it get modified? It may or it may not. Either one would be useful, but this way nobody else can hold a reference to the slice because it becomes useless to them.
Every language has idiosyncrasies.

The issue with Java is that right off the bat you are presented with bloat. Just to have a main function requires a class (and people realize this is wrong, which is why Kotlin and Groovy fixed this).

Want a build system? You have to learn a whole another language essentially, like ant/maven/or gradle.

Want to have logs? You have to use a library that has its own xml configuration files that specify behavior, in their own format. Oh and that library may have glaring vulnerabilities where logging something results in FETCHING CODE FROM THE INTERNET AND EXECUTING IT, BY DESIGN. Same goes for most any other public library that is widely used.

Oh and btw, its bad practice in making your class members public, you should make them private. But its also bad practice in writing getters and setters - instead use a library that hacks the AST and writes functions there that are not visible in the code, for which you need special plugins for every IDE to recognize.

I honestly don't know how people deal with this and remain so ignorant to it to continue using Java.

If you want perf, then rust wins. Golang has gc.
Come on, I can honestly have a hard time taking anyone seriously that says that Go is a better designed language. Like, at times I even question the “designed” part.

They managed to create a more verbose Java 1.1 (yes, this is objectively true), with even more footguns than it had at the time. Oh, and it is absolutely not more performant than Java for most use cases - sure, it is a good choice for very basic server applications that barely allocate anything, but complex applications where allocations are significant will absolutely run faster with Java.

Depends if you want to pay for one of the commercial offerings for AOT compilation that have existed for 20 years, or rather go with the free beer offerings from GraalVM and OpenJ9.
I don't know serverless, but recently-ish (few months ago) I was testing Java memory usage on a tiny program. Something like:

    public class Main {
        public static void main(String[] args) throws InterruptedException {
            for (int i = 0; i < 60; i++) {
                System.out.printf("%d\n", i);
                Thread.sleep(1000);
            }
        }
    }
After spamming as many flags as I could find (literally listing all possible flags and seeing what looked like a high number, and lowering it), I could only get this program to use 307MB VIRT and 40MB RES memory.

Unfortunately I didn't save the flags I used.

That's more or less on par with the equivalent Node.js program on my PC (Node.js actually uses a bit more RES memory, 44MB).

So I guess as long as you can (and want to) spam a lot of flags, it's feasible to lower memory usage.

Disclaimer: Not a Java dev.

In my experience Java performance worse than Node when used with memory cap. I am not an Java expert though, maybe there is a flag I missed.
Oh great more shit to learn! I’m moving my entire bowling alley codebase to forth.
Pet peeve warning.

I'd like to propose a very simple JEP for JDK22: Let me omit the useless {} at the end of a record declaration.

I get that records are technically classes and that sometimes, you want to add helper methods, additional constructors, etc. But the canonical - and most common - usecase for records is a dumb immutable data structure, and for that you shouldn't need anything except the fields and generated methods. That's the whole idea behind them.

I always found it strange that Java has you write an awkward empty class block for the standard usecase here, while reserving the more natural syntax for exotic uses.

Do you really think they just forget about it? It has a purpose: https://mail.openjdk.org/pipermail/amber-dev/2020-April/0058...
That’s the fun thing about backward compatibility. You can never clean up technically supported things that were never intended.

It would be cool if we could have some kind of pragma or alternate syntax (file extension?) that gets rid of these unwanted ambiguities every decade or so. How to do that while avoiding the whole “Perl 6” can of worms might be the hard part though.

Rust editions? They work on per crate, rather than per file level though.
In Java you set the language version per source file, and there are occasional and uncommon source incompatibilities, but it's still not worth it to introduce a common incompatibility (which isn't really the case here, anyway).
They still all compile to some set bytecode version, right?
The target bytecode/standard library version can also be specified on a per-file basis (we have both -source and -target options). But while the VM can load a classfile of any version since the beginning of time, the javac compiler supports only a certain number of versions back in terms of source version and target version (e.g. you can't use a JDK 19 compiler to target JDK 7, but you can ask for the same language, API, and bytecode level as 15).
Perl 5 has that.

Perl 5 seems to have all these annoying boilerplate lines that you need to add to every file in order to get “Perl The Good Parts”. But I think (I read) that they managed to boil it down to just one line.

These things are what I love the most about JEPs. Someone already discussed it.
Thanks for digging out that thread, that really gives some insight!

I still disagree though. First, there is precedent with interfaces and abstract methods, which also leave out the method body and terminate with a semicolon.

Second, the point here is that you almost always leave the body of a record empty, while you rarely do so for a class or method.

They are worried that if you use arcane constructs like non-static initializers, the syntax might become confusing - but are fine if you have clutter in the common case. That seems backwards to me.

Edit: You can construct the exact same confusing situation that the thread warns against already today, with abstract methods:

  public abstract void foo(); {
    System.out.print("I don't have anything to do with foo!");
  }
Somehow we still lived.
> You can construct the exact same confusing situation that the thread warns against already today, with abstract methods

The email exchange didn't talk about that kind of confusion; in fact, it said `;` was an option. It just said that saving one or two keystrokes isn't worth it to break the rule that type declarations end in `}` while statements end in `;`.

> there is precedent with interfaces and abstract methods, which also leave out the method body and terminate with a semicolon.

Abstract methods aren't type declarations and they have no body. Also, they've been in Java since day one. It's conceivable that down the line, people will be so used to records that we'll allow `;` to terminate the definition. It's just that we've gone down from a page of code to one line, and adding another rule to save one character isn't worth it at this time.

First of all, thanks a lot for the reply. I didn't expect to get an answer by the actual authors of the feature :)

I think it's not really about the keystrokes (though { } is harder to type on my keyboard than ; ) but more that this technically opens a new class block, which gets treated as such by build tools, IDEs, etc.

E.g. formatters want to put the braces on different lines by default and are generally tuned to put class blocks front and center - because with all the other occurrences of class blocks, that's the sensible thing to do. With records, it just undoes the neat "just one line" property.

Yes, you can add custom formatting rules to stop that, but that's additional effort - you also have to ensure everyone uses the new formatting, etc.

It's also more cognitive effort to parse the code: Imagine the GROUP BY clause were mandatory in SQL and if you didn't want to use grouping in your query, you'd have to write something like "GROUP BY 1". Certainly doable but makes queries harder to read.

> type declarations end in `}` while statements end in `;`.

That rule already has lots of exceptions, e.g. methods are not type declarations (like you said) and neither are initializers. Nevertheless, both use braces and leave out the ; at the end.

> I didn't expect to get an answer by the actual authors of the feature :)

I am not an author of that particular feature, but I work with them on OpenJDK.

> Yes, you can add custom formatting rules to stop that, but that's additional effort ... It's also more cognitive effort to parse the code

Perhaps, but using `;` has its own downsides (it's different from all other type declarations both for readers and for the language's grammar). The choice is never between something good and something bad, but between two things that are both good and bad.

Given that a record can save you tens of lines, on the whole it was decided that it's not worth it to add a new rule that saves a single additional character at this time. It can always be added later.

> That rule already has lots of exceptions, e.g. methods are not type declarations (like you said) and neither are initializers. Nevertheless, both use braces and leave out the ; at the end.

That's not the rule, though. I didn't mean that only type declarations use {}, but that all type declarations use {}. I don't think there are any exceptions.

There is plenty of precedent for using ; instead of { } if the { } is empty, e.g. interface methods, or "while (foo());"
In C# you can declare a record like a method body.
(comment deleted)
> I'd like to propose a very simple JEP for JDK22: Let me omit the useless {} at the end of a record declaration.

Meh. Pet peeve warning: I hate this. Sneaking in stuff like this that might save 1 or 2 characters every hundred or thousands of lines is just frustrating.

If I'm regularly discovering cute one-off things like this in a language I work in then I'm gonna hate the language. And unsurprisingly, I hate most modern languages.

Unless your doing mostly lisp programming, it does sound like you hate most languages (which to be honest, is the position I'm in so wouldn't surprise me)

To turn it around, what languages do you love?

Clojure is my favorite.

I also rather enjoy Elixir - it has elisions like this, but there tends to be deeper fundamental underpinnings as to why it works, why it was included, and it's more broadly applicable. So rather than memorizing minutia you can understand those underpinnings.

Once I got past some of the weird syntax rules of Erlang, I really liked it. It was actually the first non-C-like language I "got".

I also somewhat enjoy Golang. I don't think baking concurrency into the actual language was necessary to get the ergonomics it provides (repeating a mistake Java made), but overall it's better than most others.

I think Java does an OK job of not being too susceptible to this. For people that want it there's always Kotlin, but I'm happier not using it. The evolution of Java seems to have a broader logic behind it, and they seem to be adding things with an eye towards the sum being greater than the individual parts.

Of course, for work, I'll use whatever is necessary for the project. Which is currently C# because we're doing stuff with Unity.

My pet peeve is that all properties could be in the class body, and then both classes and records could enjoy object initialisation a la C# if the committees that be ever wanted to add any useful ergonomics to the language.

Alas.

I don't understand the syntax for records at all. Pretty much every Java codebase is going to have "POJOs" already e.g. a class with a few fields and getFoo() methods, after all that's why they introduced records in the first place. If they'd had the attributes and the methods together inside {} like a normal class, and if they'd called the getters according to the naming convention which has established itself pretty much as a constant over the last 20 years, you could upgrade your old POJOs to records pretty much by just replacing "class" with "record".

Come to think of it I don't really understand why they had getters at all. Just go with a .foo attribute syntax. I can't imagine if I define a record and start overriding the foo() getter to do something other than returning foo I'm going to have a good time come PR time ... I've certainly never seen code that does this.

The difference between getters (or properties) and attributes (or fields) is that getters are a real function and attribute access does not use a function. The attribute access is less work because you don't have to do a method dispatch to get the value. (At least historically; the method dispatch may be optimized out now for basic getters.)

Most of the time your getters will just return the attribute, but there are situations where you don't have an attribute backing your property:

1) You're renaming the field, and you can't update all uses at once. You can create a synthetic property with the old name which delegates to the new name.

2) You want to lazily compute the property only when requested.

3) You want to perform a side-effect every time the field is accessed

Tantalizing to know how many useful features are being added all the time and yet so many apps are stuck on JDK8.
I see more and more the JDK11 to be an absolute minimum. (which leads to issues because of that [still mysterious to me] move to modules management)
I've been playing around a lot with the pattern matching preview features in a small personal greenfield project, and the requirement to explicitly spell out the generic type params every time always catches me off guard and sorta craps up the code a bit. Looking forward to just using diamond operators there.

I also can't do nested record destructuring because it causes an ArrayIndexOutOfBoundsException in the Eclipse Neovim LSP. The "bleeding" part of bleeding edge!

> the requirement to explicitly spell out the generic type params every time always catches me off guard and sorta craps up the code a bit

I'm glad it's not just me! I was implementing Either<T, U> the other day, and found writing Left<T, U> and Right<T, U> a little dirty. Progress is progress though.

Its kinda funny reading these. Kotlin and Groovy exist, which fixed a lot of the issues with core java (like for example requiring a class around a main function), but yet Java developers are completely oblivious to this. This kind of stuff should be in the core language.

Im convinced that Java exists solely to create positions within Software Engineering industry. It requires you to write more code than necessary by design.

It's not a 1:1 replacement. Some things are better and some are worse with Groovy and Kotlin. Not everything is "fixed".
If google moves their entire app development workflow for Android to Kotlin, its pretty much a 1:1 replacement.
That's like saying if Java can adopt more features we don't need Kotlin? Doesn't help either way.

It doesn't help either way. Kotlin definitely has its quirks and issues. Multiplatform means they're trying to re-invent everything and yet don't have all the resources to. With Kotlin moving to KSP for annotation processing this has been another source of pain with library developers having to maintain 2 variants. Not everything is KSP supported either. It's not quite so straight forward.

Yet they caved in, added Java 11 LTS to Android 12/13 and Java 17 LTS is coming this year.

It turns out that being unable to use Java libraries is a big issue when one doesn't want to re-create the Java world in Kotlin.

Java projects compile 2x faster than Kotlin projects and don't hang the IDE. Kotlin is nice for small stuff but has severe issues when scaling up.

Also, Java is far, far simpler to code in compared to Kotlin. Modern Java is quite pleasant. The language advantages of Kotlin frankly aren't enough to switch. It may have been supreme in 2016, but Kotlin has lost most of its head-start now. Java has caught in both mature language features and lean libraries.

And folks do prefer simpler languages. There is a reason that Go is popular.

I'm really looking forward to JDK 50 with its revolutionary Pattern.quotemeta() method which will be able to do what Perl has been doing for nearly 30 years.