As far as the Java platform (AKA "the JVM") goes, Kotlin is painting itself into a corner. Kotlin was designed in 2009-10, in the Java 7 days, around the time of the Oracle acquisition, and at a time of stagnation for Java due to Sun's decline. At the time, Android was also quite similar to Java. Kotlin was a great design in those conditions. Things are very different today.
Kotlin's design goals are now contradictory. It seeks to be a low-overhead language, i.e. provide abstractions that don't add overhead over the target platform, give access to all platform capabilities, and at the same time target multiple platforms -- Java, Android, LLVM and JS -- over none of which does Kotlin exert much influence (maybe a bit on Android). Since 2010, Java has moved away from Android, to the point that there are very big gaps between the two, and they're only growing.
By both trying to target multiple platforms (with no say in their design) and trying to add little or no overhead, Kotlin will soon find itself in a bind. It's coroutines are in conflict with Java's upcoming virtual thread's design, and its inline classes will cause problems with Java's Valhalla vs. Android. Kotlin will have to choose to either give up on low-overhead abstractions, give up on some of its platforms, give up on giving access to full platform capabilities, or split into multiple languages, each targeting a different platform. For example, if Kotlin's inline types will make use of Valhalla, then they won't work on Android, at least not without much overhead.
TL;DR: A full-capability, low-overhead, multi-platform language is hard to pull off in the long run when you have low market share on all of those platforms (except Android) and little or no influence on any of them. This was viable under some accidental circumstances, but those are no longer holding.
I've been using Kotlin for a long time for backend/server dev personally and professionally. I've been feeling this more and more recently. I've said a couple times to my colleagues I've backed the wrong horse.
I had been making strong use of multi platform features. The end goal had been to easily move a piece over to a native image for server less if need be. Or output SDKs for Java script libraries. As an example I'm working on a multi platform micro-orm. But due to lack of cohesive reflection. I have to store the class package name in a map to reflect the type on all three platforms.
As to the note about inline types and Valhalla. Or loom for that matter. I have a feeling that will be buried as a compiler option. That needs to be amended in a build file. I have had to do this with JS, native, and a JVM
I'm finding that multi platform out side of mobile and JVM. Are not well polished. Additionally you're carrying a lot of baggage over from the JVM. In regards to it's type limitations and memory management. At the same time it's very impressive to easily target all three platforms. But it's a very difficult task.
Combine this with the few back-end places I've seen using Kotlin for the back end. Limit the features that can be used. To the end that the next Java version can primarily satisfy their needs. I've seen more effort coercing developers not to use sealed classes, null coalescing, co-routines etc. That could just be avoided by staying on Java.
I think it's a good language. It feels like a commonality of a number of the best practices. I've been able to migrate python, ruby, and typescript devs to a ktor setup and have them productive in a week or two. Gradle for all it's warts, I think is a pretty good build system. There is a rich eco-system of existing libraries. It has good performance, easy type semantics to grasp without getting in the user's ways. I feel like it's Typescript with a better build system (opinionated), and light pattern matching. The biggest API stability issue I've had is Gradle. I've carried projects from 0.11 to 1.4 with just nominal code base changes, but big build file changes.
The biggest focus is mobile, followed by Spring back-end. I have been very critical of Spring in my prior posts. There is a road map of Ktor, their in house web frame work coming soon. I'm curious to see where the language goes next. I'm finishing up one project in Kotlin but am eyeing Rust as a possible replacement
I share many of your feelings toward Kotlin as a language. I've said a few times that Kotlin is the best JVM language, but that's it. Even if the Native and JS "ports" or whatever were well-polished, it's still exporting the limitations of Java with it. That's... not awesome.
But are there any other options for multiplatform besides JavaScript?
Also, for what it's worth, I love Rust. The lack of garbage collector is overkill for web backends, but I don't care. I spent years doing C++, so it doesn't bother me to think about some of those things. Even if it feels slower to develop in, it's a really great language IMO, and I love the feeling of "if it compiles, it probably works".
They tried addressing some of the limitations of the JVM with native and co-routines. Making multi thread objects mutable, to not allow for race conditions. From a recent conference they backed off because they couldn't express immutability as a good idea.
I started multi platform with F#, Xamarin, and Fable. That worked, but F# doesn't have a wide community. The few F# teams I had been on we spent more time discussing mathematical proofs than delivering business value. I'm also getting to this point now, where I'm trying to build a simple SPA. I'm spending more time wrangling the tooling than delivering features. So that leads too.
I don't think there are good multi platform languages, besides JS. But I think we have a set number of transport means. Websocket, HTTP, HTTP2 to client, with various protocol, and content types. Back end say TCP, Kafka, MQTT, STOMP, etc.
I've been pivoting my focus from mp to schemas. JSON schema, backs async api, open api, and a number of others (aws cloud formation, github, gitlab, etc). With that schema you can now know the transport mean, and the object to be communicated. Additionally with the possible error responses.
The disconnect though is how are those schemas produced, and verified. Having a web framework generate usually results in badly titled methods, or a lot of additional cruft. I usually go contract first. But there are very few frameworks that take in and validate a schema. This leads to a disconnect, I've seen, where the server just doesn't match the schema. I had written a pojo generator for spring, that consumed a schema via gradle and output the response classes, and strongly typed the url paths. But it was met with a ton of resistance, namely because it wasn't maven.
If your back end consumes a schema, and starts the server. Then you know it adheres to the schema. This also allows for asynchronous development. Once the schema is finalized. Mobile, web, and back-end can all work on the same feature. As there are a number of stub container services, that spin up a service container used for integration testing, and generating out client SDKs. The few times I've been able to execute like this, it worked great.
Rust is a really great language. Having come from ocaml, it feels like a natural extension. My hesitation is two fold. One I have been using Kotlin + Intellij for ten years or so. I'd have to relearn a lot of my workflow, and port a lot of helper libs I wrote. Two I can never see using it professionally. All the Rust interviews I attended were white boards of algorithm, and calculus questions. I'm not a math person so that's not really feasible. I do want to take it for a spin in the future. Actix looks darn impressive.
I like your take on Kotlin being Typescript with a better build system. I often show our Kotlin devs our Typescript apps and say, "see, it's very close... we just add semicolons". Many of them are former Java devs, so they're used to blindly believing, "JavaScript == bad". (yes, everyone can see what I did there) I like showing that it can actually be quite good in some ways. For high performance db crunching, I strongly prefer Kotlin. But for pure network services, REST request to sending files via SFTP, Typescript is really nice.
That said, there's still a lot to be desired in JS's ecosystem. The difference between JS libraries and Java libraries is huge.
The package manager (npm) also has a lot of room for improvements. I have a small SPA with like 15 files and a couple of dependencies, where updating one dependency has broken my environment and I had to reinstall another underlying dependency (typically a typings package). I just miss Maven.
To say that TS is like Kotlin is true superficially, but I must say I have faced many more "wtf" moments with TS because of weird glitches of the tooling, or packages, or something similar.
I really want to love TS and JS, but the more I develop in it, the less likely I am to reach for it in my next project.
This sort of echoes what I meant by in my opinion the build system is better on Kotlin, if not more complex. My opinion of course.
Using a library from a big tech vendor I found a number of issues with the definition files. That led to me tossing in ts ignore all over the place, and asking if I could file bug reports on company time. Lerna is the closest for a good multi module project. But that has a number of quirks.
As an aside I keep harping on multi module. But I find they really help with service boundaries, and flow of the application. Allowing dependencies to flow from bottom to top like a pyramid.
The other day I was working on a new proof of concept tool. I started with type script because that's what the team was using. But after cloning the demo from the vendor, it didn't minimize into proper java script. It seemed to be a known bug. I redid it in Kotlin in an hour. Because of the syntactic similarity, the team was able to pick it up. Worked on the first try. Now we just need to fix the TS build.
Incidentally these tooling issues are the bigger plague of the js multi platform. Dukat while great is only as good as the type definitions. There are also so many incongruities with the output. I've come to if I just output js I'm fine. But don't try consuming js. This also was the issue with rescript/reasonml to me.
I can output common websocket/http clients via ktor. Data classes, and other elements. But we have async api, open api, graphql, etc. The core of the multi platform driving business logic is being eaten by good automated tools. What's old is new.
Replacing current courtoutine implementation to use Loom threads or inline classes to use Valhalla are both implementation details that should not at all change the user facing API and complexity.
Your second point somehow stand: exploiting such optimizations will either need a runtime check or to be enabled automatically based on your JVM target specified in your gradle/maven.
As for the long term, google devs are heavily contributing to Kotlinc and I hope they will pressure Android architects to replace dalvik with openjdk.
> Replacing current courtoutine implementation to use Loom threads or inline classes to use Valhalla are both implementation details that should not at all change the user facing API and complexity.
This is not accurate.
Re Loom, the entire Java platform will be built around a "single colour" structure. Kotlin, like C#, is based on a split, two-colour, model. It is true that under the covers it could map both colours onto the same one, but that will mean that Kotlin adds a lot of unnecessary complexity, and possibly make it harder to target multiple platforms (i.e. a lot of Kotlin code that will work well on Java will not work well on Android or JS).
Re Valhalla, it will allow multi-component inline types -- that's a user-facing change -- but those won't work on Android, at least not without significant overhead.
Agreed, although I don't want to go so far as to say color is that intrinsic but they are different features with different goals.
Loom is about many blocking green threads that are scheduled without you thinking about it. Coroutines are meant to support UI programming where you deal with a marshaling the app flow to and from a main thread. Coroutines are more verbose but they handle different use cases than Loom.
That said, Kotlin coroutines are just a library anyway. Its a dependency change not a language change to swap out the implementation.
> Re Loom, the entire Java platform will be built around a "single colour" structure. Kotlin, like C#, is based on a split, two-colour, model. It is true that under the covers it could map both colours onto the same one, but that will mean that Kotlin adds a lot of unnecessary complexity, and possibly make it harder to target multiple platforms (i.e. a lot of Kotlin code that will work well on Java will not work well on Android or JS).
Function colours are a useful modelling tool regardless of whether the underlying platform requires it. That's sort of like saying "everything is eventually just bytes anyway, so types are unnecessary complexity".
Of course, there are languages trying flatten everything into a single type. But personally, I'd rather not be programming PHP when there are better options available.
> Re Valhalla, it will allow multi-component inline types -- that's a user-facing change -- but those won't work on Android, at least not without significant overhead.
Not sure how that's any different from a library's perspective than "this API isn't available on older JVMs, so don't use it if you want to target Android".
> Function colours are a useful modelling tool regardless of whether the underlying platform requires it.
Without getting into the debate over what valuable information the "async" colour communicates on a platform where, unlike in JS, global state changes could occur at any time due to thread concurrency, any thread can be suspended by either the VM or the OS at any point for any duration, and "async" is no cheaper than "sync", the more practical problem is that Kotlin does not know what colour the platform's operations are. This means that some arbitrary mixing of colours would work on one platform but might not on another.
I know some two-colour frameworks use BlockHound, a dynamic "colour detection" tool, but even as a dynamic tool and even today BlockHound sometimes gives wrong results because it doesn't keep up with the frequent changes to the platform.
> Not sure how that's any different from a library's perspective than "this API isn't available on older JVMs, so don't use it if you want to target Android".
Because it's not about libraries or versions you can upgrade but core language capabilities that differ by platform. It could be acceptable, but it means that there are different Kotlins for different targets.
We get a language whose both syntax and/or behaviour differs by platform, and isn't a first-class citizen on any but one of them.
> I hope they will pressure Android architects to replace dalvik with openjdk.
Android hasn't used dalvik for ~5 years now. Switching from ART to OpenJDK runtime is both non-trivial in complexity (can't break existing apps), and doesn't bring any obvious benefits, either. OpenJDK isn't tuned nor optimized for the constraints that Android operates in, and ART isn't exactly a slouch, either.
The only benefit it brings in theory is just updated bytecode support, yet Android is still going to be stuck with dex, and still has the backwards & forwards compatibility issues, and OpenJDK doesn't help that situation at all. Nor have there been any significant bytecode changes/improvements in Java anyway, so you still don't get any benefits from it.
> Nor have there been any significant bytecode changes/improvements in Java anyway, so you still don't get any benefits from it.
Java's core capabilities aren't just expressed as bytecodes -- there are lots of intrinsics, too, which, in this case, mean "native" capabilities exposed as library APIs but implemented in the VM and cannot be implemented in bytecode. Neither Panama nor Loom add or change any bytecode instructions, yet they drastically change the platform's core capabilities. Same goes for the module system -- it changes the accessibility/visibility rules in the VM but does add or change bytecode.
Similarly Loom isn't necessarily useful for client-side apps, as coroutines already fit that role and full green threads isn't useful. Most likely Loom would be a regression for mobile apps, as keeping key threads responsive is more important than maximizing throughput. And it definitely isn't going to be as tuned for things like big.LITTLE out of the gate as the existing Linux scheduler is.
The only ~significant area of issue here is those trying to build commonly portable Java libraries. But there's not much in common in practice here, and that shouldn't be the singular deciding factor.
But the meta-point here is how much of the "use openjdk instead!" crowd is simply overly familiar or buying in to OpenJDK hype & general JEP awareness, and simply isn't following along with what's going on with ART on the other side of things? ART isn't a bad runtime, after all, it's actually quite good. And it's had a lot of useful things that OpenJDK doesn't or only just recently got (like specifying what was null when an NPE is thrown - ART's been doing that for years)
ART can indeed ignore Loom, or better just map the virtual thread API to regular threads. It'd not work well for things like generators but those aren't a target of Loom at the moment anyway.
The lack of other features in ART does hold things back though. The list of bytecode and API features that ART doesn't have keeps growing and some would be useful on mobile. Panama will add a better FFI and a SIMD API, when will Android get that? Never? That would be a pity. What about Truffle/Polyglot? What about some of the neat tricks allowed by proper invokedynamic?
Other than licensing I do wonder why Google can't just bring the nice bits of ART across to HotSpot. It would save library developers a lot of heartache.
Sure, but my point was about similarity/compatibility. It might be the case that Android has suitable alternatives to Java's features, and it's possible that they're even more suitable for Android's needs, but the point is that while the two platforms were quite similar ten years ago, and a single language could target both with few if any tradeoffs, this is increasingly becoming tenuous as the two platforms become dissimilar in fundamental aspects. A language that attempts that will increasingly find itself needing to make tradeoffs that it didn't need to, say, five years ago, or even today.
In java7, the concept of 'I want to typecheck this expression, and if it is of the type I want, I want to do things to it based on that fact' was unwieldy in java:
-- JAVA 7 CHECK-AND-USE --
if (x instanceof String) {
String y = (String) x;
y.toLowerCase();
}
kotlin decided to address that:
-- KOTLIN CHECK-AND-USE --
if (x is String) {
x.toLowerCase()
}
within the 'if', x 'updates its type' automatically. Note that if java were to copy this, method dispatch depends on the compile-time type of the arguments, so if java were to apply this behaviour to its instanceof operator, that would break backwards compatibility (existing java code would mean something else just because you updated java versions). The obvious thing happened: Oracle / the JCP rejected this outright. Hence, it doesn't work that way in java and never will.
But this problem WAS tackled by java, and in a much different way: Java has generalized this concept as pattern matching and went all in on that.
-- ACTUAL FUTURE-JAVA --
// preview feature in 14, will be in 15.
if (x instanceof String y) {
y.toLowerCase();
}
// -OR--
if (!(x instanceof String y)) throw new IllegalArgumentException();
y.toLowerCase();
and, taking pattern matching to the next level:
// will likely be preview in 15 or 16.
// Given:
value class Point {int x, y; }
if (p instanceof Point(x, y)) {
// you can use x and y (both int) here
}
Which goes much further than kotlin and is quite different. So now kotlin has 3 options and they are all bad:
1. Also adopt this syntax. But now there are 2 different ways to do the same thing, so kotlin is now the language that feels like a jumbled mess that needs cleaning up, with pointless style debates and an increased learning curve for no good reason.
2. Ditch their existing syntax and adopt this syntax. That means kotlin breaks their own backwards compatibility, and everybody needs to either accept they can never update their kotlin, or they need to find all spots in their codebase that uses the old construct and update it.
3. Don't adopt this, and be in the situation that java has _more_ language features that kotlin. Or adopt pattern matching differently, at which point the idea that it's 'easy' to switch from java to kotlin starts taking a hit... and likely kotlin's design will start to feel jumbled because features are spliced on ad-hoc and mostly informed by dueling concerns.
Because they'd be using 'is' instead of 'instanceof'? That just really doesn't strike me as a meaningful difference.
Hell, they already have a lot of way more crazy changes (the radically different lambda syntax, different function signature, functions outside classes, extension functions, etc). By your reasoning they're already way past the point where "it's 'easy' to switch from java to kotlin".
It's been a while since I've used Java and it seems weird to me to see instanceof used to check values instead of types. That sounds a lot like instance of being used instead of .equals(). Why not?
if (r.equals(new Rectangle(Point(0, 0), Point(1, 1)) s) {
s.doStuff();
}
Are they really planning to use instanceof to check for equality?
It's not exactly the same as equality checking, as each has its own uses. You can override `equals` to reflect specific semantics. Say for example you have a non-public ID field for your Point class that is used to determine uniqueness, such that points with different IDs are not equal regardless of their x, y values (maybe not the best example, but the point holds, arguably however, that would be bad practice for records anyway).
Secondly, using equals as per the code you provided incurs at least 3 allocations (1 Rectangle and 2 Points), whereas using pattern matching there are no such allocations.
Furthermore, and probably the main point of pattern matching, is that it allows for "deconstructing" records into variables so that they can be examined individually. I can handle any Point on the x-axis at y = 0 by simply matching against `p instanceof Point(var x, 0)`, or all rectangles with their first point is the origin by matching against `r instanceof Rectangle(Point(0, 0), var p)`, it's much cleaner and clearer than writing something like:
if (r.getFirstPoint().x() == 0 && r.getFirstPoint().y() == 0) {
var p = r.getSecondPoint();
// ...
}
Not to mention once we have sealed types we can do something like:
var area = switch(shape) {
case Circle(var r) -> Math.PI * r * r;
case Square(var s) -> s * s;
case Rectangle(var l, var w) -> l * w;
...
}
Pattern matching has been available in many other languages (e.g. the ML family of languages, and some JVM languages like Scala), and now Java is also gaining this feature.
Off-topic with respect to Kotlin but relevant to the Java platform:
From your perspective, what are Clojure's prospects for contemporary and future alignment with the JVM?
After all, Rich Hickey built the core in 2006-07. Looking at his graph[0] of code introduction and retention in his HOPL-IV paper[1] might imply that either he's that good at the core abstractions or possibly the language could suffer a similar set of limitations as commented about Kotlin above.
I think Clojure has a very different design philosophy and very different goals. Specifically, its abstractions do add overhead -- be it due to immutability or lack of typing -- and that's perfectly in line with its goals. As such, it flies higher above the Java platform than the Java language or Kotlin, and is less sensitive to changes in the underlying platform, as it doesn't try to always closely reflect its capabilities.
I think you might be right. But isn't this just the general risk of dealing with a "stagnated language/tooling"? Either you wait for it to go out of sleep mode and catch up. This might never happen, and is thereby a risk. Or you fork off to your new system which attempts to fix the issues you observed. This might require a serious investment. And maybe it's not useful in the future, since the original tool might catch up and most of the people will stick with it.
So now you evaluate the 2 options in terms of risk and short/mid/long-term benefits as usual. And I think the Kotlin designers and all users which jumped onto the platform made a sensible choice.
I really love the idea behind loom - but it's still not generally available. Kotlin coroutines are, and imho solved sane concurrency for mainstream users. If I would have to write a massively concurrent application on the JVM about 1-2years ago, Kotlin could certainly have been my way to go. In 1-2 years it might be Java+Loom.
Last but not least I would like to point out that Kotlin is extremely well designed. Imho it's coroutine system is the best in industry right now. It's extremely configurable, and the inclusion of structured concurrency right from the start to encourage good designs makes a lot of sense! I would not be suprised if Kotlins designers already have decent plans on "what do we do if Java integrates Valhalla/Loom/etc"? And I think it's pure existence pushes the standards, and has a positive impact on the design of Java and other languages.
> And I think the Kotlin designers and all users which jumped onto the platform made a sensible choice.
Oh, absolutely! And don't get me wrong, I think Kotlin was the right thing to do ten years ago -- Java was not in a great shape back then (in fact, Sun drastically cut investment in the core platform) -- and maybe even five years ago. I also think it was very well designed -- very much in the "Java spirit" -- although I think it's taken things a bit too far recently for my taste.
> Imho it's coroutine system is the best in industry right now.
I think that coroutines for a platform that's already designed around multi-threading are a bad idea altogether (this goes for C# as well) unless the language has some very specific constraints, like C++/Rust. Some might disagree, but I don't think those would be people who've had experience with Erlang or Go (although those platforms, like all platforms -- including Java, of course -- have their own problems). Nevertheless, for quite a few it's certainly better than nothing.
> I would not be suprised if Kotlins designers already have decent plans on "what do we do if Java integrates Valhalla/Loom/etc"?
I'm sure they do, and I'm sure their solutions would be great, but they'll need to sacrifice some of their goals. In any event, it is no longer the "there's nothing to lose" proposition it used to be.
> And I think it's pure existence pushes the standards, and has a positive impact on the design of Java and other languages.
Maybe, although Java (the language) has so far taken little if anything from Kotlin (most of the inspiration to recent work has come from ML, and even Scala to some degree). If there is one Kotlin feature that I think might ultimately make its way to the Java language it would probably be nullability types; I think that that's its most impactful contribution to the design of other languages, too. What mostly pushed Java forward in recent years is the increased investment by Oracle, and competition from other platforms. If I were to pick a positive impact Kotlin has already had on the Java language, it is perhaps demonstrating that there is appetite among programmers in more conservative languages (as opposed to Scala and Haskell programmers) for new language features beyond lambdas.
> I think that coroutines for a platform that's already designed around multi-threading are a bad idea altogether (this goes for C# as well) unless the language has some very specific constraints,
I would actually go one-step further on this: Async processing on a platform that is designed around multi-threading is a bad idea. I think pure multithreaded programs are fine (although data-race and deadlock prone, but tooling like thread-sanitizers and Rust can help here). Pure async (something callback-like) programs are fine. The mixture is pure hell. If I see a multithreaded library which takes a callback, I'm sure 95% of its end users are using it wrong, and are not even aware on which thread the callback will be invoked. This number is based on publishing such libraries, as well as leading teams with junior engineers trying to use them.
So it would be great to avoid to use that idiom at all.
However the reality is that on platforms like Java and C# those are already reality. We have mainloops, GUI eventloops and networking eventloops where all code is bound to a certain thread and can not be executed somewhere else. So either we rewrite those, or we find a paradigm which makes life somewhat easier for them. And I think coroutines do that - at least you are sure the continuation brings you back to the same thread/execution-context you can been before (unless you overwrite it with one of the million and sometimes non-obvious settings). Therefore I think they are beneficial. It might be nicer to get rid of async-processing at all, but that would require the development of new UI frameworks which follow different idioms.
One interesting question is however: Are they actually a good fit for Rust - where common async idioms don't fit well anyway due to borrow-checking, and the main use-case at the moment are request-based network applications instead of UI frameworks. I don't have a clear answer for that one yet. I think in a lot of ways stackful coroutines (virtual threads) might have been a lot easier to deal with. But I also understand the desire to not to have a runtime.
C++ and Rust are low-level (or "high control") languages with constraints and goals specific to such languages. For example, they frequently interact with C and so they leak implementation details (like stack addresses); they have lots of pointers into the stack; heap allocation is relatively costly and requires explicit bookkeeping and management; they prefer constructs with well-known worst-case costs even for the price of having low abstraction (“high abstraction” being representing many similar things with one construct, even if they differ in implementation). My point being that the design constraints for low-level and high-level languages are very different, and what's good for one is often bad for the other.
> Kotlin will have to choose to either give up on low-overhead abstractions, give up on some of its platforms, give up on giving access to full platform capabilities
It can be just reasonable mix of all of this.
> if Kotlin's inline types will make use of Valhalla, then they won't work on Android, at least not without much overhead.
Oh, I'm sure they'll do something reasonable, but whatever it is, it either significantly scales back the goals or it turns Kotlin from a "there's nothing to lose" proposition to a "there are new tradeoffs and added risks to consider" proposition.
Assuming Android doesn't support Valhalla at all, I suspect they'll just introduce an Android specific backend in which inline classes with >1 member are compile errors. The language is already slightly different between platform targets anyway so it's no big leap.
I think JetBrains thinks too much of themselves, fueled with Google wind, they are now trying to turn Kotlin into a platform of their own, and as proven by Kotlin/Native, their expertise is really just making IDEs.
Too many recurring memories from Borland of yore with Delphi, when I see how JetBrains is trying to push Kotlin.
That isn't up to the game versus JVM or any existing AOT compiler for Java.
It compiles slower, doesn't produce machine code of the same quality and requires a separate semantic model for heap management, the reason why recently they had a blog post about having to redesign it.
EDIT: Exactly for my experience with those languages and what went wrong with their adoption is why I will never use anything that isn't a platform language on production code. Either it comes with the platform SDK or no bother.
In Kotlin's case that is Android, as long as Google doesn't do one of their reboots and decides to focus on ChromeOS or Fuchsia instead.
That doesn't prevent building an abstraction layer and plopping Android onto a different kernel, of course. After all that's what Microsoft did with WSL.
As Android engineer since 2013, I'll say this is patently untrue. It is really difficult to get Android to work on non Linux OS's without virtualization.
All the best for them, as long as the community takes the attitude to appreciate JVM and Java for giving birth to Kotlin, instead of bashing Java as if Kotlin could stand on its own.
You are biased because you don't like that the age of companies selling expensive development environments is over. And you jump in to defend Oracle every discussion.
I respect your knowledge and breadth of experience, but your biases are apparent.
It could, but Java the language definitely isn't bad. Sure, it's verbose, but it's pretty simple to grok overall.
I agree with pjmlp (and I don't even work for Oracle!). I think that once Java has caught up with pattern matching syntax, data classes, fully integrated Loom and Valhalla etc there really isn't a need for Kotlin on the server-side anymore.
For Native or frontend stuff it's definitely always going to have to play catch-up and try to shoehorn wildly different semantics into the same language somehow.
So I guess it'll end up as a niche language on Android, ultimately. Not necessarily a bad place to be, though!
It'll never get rid of everything-is-nullable, though. That's honestly my biggest issue with Java. I could definitely complain about a bunch of stuff with Java, but the nullability situation is the worst.
Also, everyone in this thread is talking about Loom and Valhalla. Are those actually going to land at some point? I was starting to assume they were vaporware.
There is a reason why many people (including me) perceive Java as relatively bad. The language paid a great deal of resources to keep backwards compatibility, which is definitely a thing. They couldn't even just remove the unsafe package even though it was specifically announced to not be compatible with future versions, because of big vendors.
And this has a price. Bad language features stay, they make it difficult to introduce new stuff. Also, Java is very conservative in picking up new things. Saying "once Java has caught up" ignores that Kotlin, at that point in time, will be even further ahead of Java most likely.
And both of them will never reach feature parity with Scala. ;)
I can't address your specific experiences with Java, Kotlin, or Scala but even just lambdas in just Java took a ton of wind out from beneath their wings.
It just hasn't shown to be a race to feature parity in practice. Enough of the Kotlin and Scala user bases just really do want a better Java, often in just one or two ways.
Personally, and more controversially, I don't think Java getting pattern matching in switches or sealed classes is going to move the needle a ton. (Sorry, Brian!) It's going to be Loom and Records that really change things.
> Saying "once Java has caught up" ignores that Kotlin, at that point in time, will be even further ahead of Java most likely.
This assumes that there is much "ahead" to get and that people want more features (well, some do, but the vast majority don't seem to). If the "catching up" terminology applies at all, it certainly doesn't mean feature parity with every other language. That's like a compulsive hoarder seeing a neighbour buying a lawn-chair and saying, "nice to see you finally catching up!" Once you've "caught up" with the expectations of the majority of programmers, there's not much more catching up to do. Neither Scala nor Kotlin have broken past 5% share of the Java platform, even when Java was behind mainstream expectations.
So sure, there will always be some small percentage who like more features than the mainstream fashion, but it's been clearly shown that you can't appeal to that minority and to the mainstream majority at once. Java (the language) tries to appeal to the latter, not the former.
> This assumes that there is much "ahead" to get and that people want more features (well, some do, but the vast majority don't seem to)
You have a point there - maybe the "catching up" is not relevant to the majority of the developers. I always find that surprising but I think you are right.
Fair, but regarding the catch-up: The main difference is that Java can actively improve things both on the language side and on the JVM side. Kotlin can only improve on the language side.
Totally agree with that! Scala is already much more organized and consistent than both Java and Kotlin (no matter what some people think) but Scala 3 will make that even better - well except for the pyhton-like syntax part, haha.
FWIW I strongly dislike IDEs and avoid them at all costs (my reasons are varied and off-topic, and controversial so I won't mention them now). I've been able to use Vim + plugins to develop in a dozen different languages/platforms except Java/Kotlin. While it is doable it is a nightmare compared to other langs. A ton of Java/Kotlin/etc code is written with the expectation that the user is using an IDE, in some places I've worked they ever require a specific IDE.
I see you have your reasons so I am not going to try to sway your opinion. But other languages I have experience with, recently, are Go and Rust and there is no better platform to code like the JetBrains IDEs. I've tried VSCode myself and I know people who were trying other platforms, VI included. It's just no comparison.
Some people have strong preferences and that's fine but for general audience I strongly advise - try JetBrains IDE for your language od choice. Try it for a month and then go back to your old tool. In my case, JB IDEs are so convenient, accurate, feature rich and just fun to use that I find going back not pleasant experience.
You can't attack a fellow user like that on HN, and you particularly can't post insinuations of shillage or astroturfing. The damage comments like this cause is greater than the damage they're purporting to combat. I can tell you from long experience with actual data that most of these accusations are based on pure imagination. That's why the site guidelines explicitly ask you not to post like this. If you think you're seeing abuse, email hn@ycombinator.com so we can look into it.
pron has been a fine HN member for many years and has been commenting substantively on these topics for a long long time. You owe him an apology.
People need to be free to discuss their work here without getting flamed. For most of us, our work is the thing we know the most about. Disincentivizing people from showing up here to talk about what they know about would be an insanely bad idea for HN, and these consequences can easily happen without being obvious, so we need to err on the opposite side.
But I still suspect there is some subtle oracle propaganda on this site. I don't mean pron is part of that though, they're an employee, and naturally defend it in many discussions, and I think that's fine. I meant to call him out to include a disclosure. The 'shilling' bit was not appropriate. To clarify, I didn't mean to call him out as a 'shill'.
Well oracle employee or not they are making some interesting points. I would appreciate more discussion on the content of their post rather than just disqualifying it outright based on their employment.
He/she made his/her points of why he/she believe so. I think that this is the important part, because after that anyone can make their own minds about it.
Sure any prediction is pretty difficult to make, but languages can be "cornered" and have a harsh time to grow beyond their original umbrella, if it dont manage to be adopted in other scenarios.
Problem is, in a lot of those scenarios, its already a "blood bath" with several programming languages already doing the same.
We have seen this trend and with this historical knowledge we are free to speculate about its future as if there is no 'black swan' events, which nobody can predict.
We know that any prediction is risky, but it looks to me that he/she at least layed down the foundations of his/her thinking, and i must say it looks good as it matches with the previous experience and patterns over other technologies.
Its too crowded, and a lot of great technology are having a bad time to stay relevant, so no wonder that Kotlin will have a difficult time too. And you dont need to be an oracle to understand that.
I didn't downvote either comment, but I do appreciate the person who called out the individual's affiliation. In the current era of so much astroturfing, I feel like it's good manners to indicate when you make a comment that you are an interested party.
Kotlin's design goals are now contradictory. It seeks to be a low-overhead language, i.e. provide abstractions that don't add overhead over the target platform, give access to all platform capabilities, and at the same time target multiple platforms -- Java, Android, LLVM and JS -- over none of which does Kotlin exert much influence (maybe a bit on Android). Since 2010, Java has moved away from Android, to the point that there are very big gaps between the two, and they're only growing.
By both trying to target multiple platforms (with no say in their design) and trying to add little or no overhead, Kotlin will soon find itself in a bind. It's coroutines are in conflict with Java's upcoming virtual thread's design, and its inline classes will cause problems with Java's Valhalla vs. Android. Kotlin will have to choose to either give up on low-overhead abstractions, give up on some of its platforms, give up on giving access to full platform capabilities, or split into multiple languages, each targeting a different platform. For example, if Kotlin's inline types will make use of Valhalla, then they won't work on Android, at least not without much overhead.
TL;DR: A full-capability, low-overhead, multi-platform language is hard to pull off in the long run when you have low market share on all of those platforms (except Android) and little or no influence on any of them. This was viable under some accidental circumstances, but those are no longer holding.