After using Kotlin in Spring projects for a couple of years, I rewrote most of it to Java 17 and stick to Kotlin strictly in Android work. It's not that much different anymore with all the recent additions to Java, and as Java progresses (and the main JVM implementation which is first and foremost being developed for Java) and diverges in other directions in some very important areas (value types, Loom), Kotlin starts to feel more and more like a second-class citizen. I mean, that's what some old-timers were preaching right here on HN from the very start.
Things like Hibernate require some pretty ugly (IMHO) hacks to work properly (you need something like three compiler plugins, and spread keywords around like there's no tomorrow).
The compiler was also very slow compared to Java. The same amount of code written in the same style took 2× times to build. This may have improved.
Probably the only thing I miss are nullability annotations (after getting used to them in C#, not Kotlin).
Edit: after re-reading what I wrote, the tone feels way too critical. Kotlin is a nice language, and certainly easier & more fun to both read and write (although it's trivial to write unreadable mess by going too far with its features). It just doesn't go far enough (for me) to warrant using a separate language with all that entails.
Java has adopted maybe 20% of the things that make Kotlin better, but due to backwards compatibility it'll never catch up.
Personally I think it'd almost never make sense to adopt Java over Kotlin for any greenfield JVM project, unless the devs you hire are truly so low-skill they can't pick it up.
Kotlin supports neither structural pattern matching nor guarded patterns as they are available in both Java 18 and Scala. It's Kotlin that needs catching up nowadays.
`if (o instanceof String s) {`
Not much benefits over Kotlin's smart casts.
Guarded patterns with this version of pattern matching should be translatable to adding another "and" condition. The Kotlin compiler should have no problem reasoning with that.
---
I find positional destructuring in Scala (which works similarly in Java 19) a bad design.
It's an abstraction atop Java. Of course it plays the catch-up game. It inherits new features from Java. They can't have it instantly.
> They can't have it instantly.
Why not if Scala did it way before pattern matching was introduced into Java?
Null-safety.
Read-only interface by default - `MutableList` vs `List`.
if-expression, they just look nicer than `a ? b : c`.
---
You're right that Kotlin is not an "abstraction atop Java (the language)". It's meant to be a better Java that feels familar to Java. With that rationale in mind, it's reasonable that they left some features from FP languages out of Kotlin.
As I have said in another reply, it was a great decision to not follow what Scala did with pattern matching.
Regex is very specific. It has added records, streams, virtual threads (preview I think) working with native better, pattern matching...
Java is like C++. Everyone talks bad about it but at the end of the day it is one of the most Getting things done language.
I am not sure why I should use Kotlin. Llokd nice! But for sure docs and support are not even close to Java.
One excels at helping you shoot yourself in the foot. The other gets things done…
One could argue C++ gets even more done, since it is appropriate for use in more contexts, like firmwares/drivers, native SDKs, games, etc. Java's main use cases have strong competition in languages like C#, Go, C++, Python, etc.
Of course some people just rant about it. But did you guys use it a span of time long enough to really know how good or bad it is actually?