Kotlin 1.4
blog.jetbrains.com
blog.jetbrains.com
Normally I'm quite reluctant to start a new project in a new language, but Kotlin edited on IntelliJ just seems so very smooth. I'm doing a side project which is a game, where most of the website parts are Kotlin.
Most of what I'll say will be a bit vague, I mainly write Python and C++. I'm also not too clear on what benefits come from the language and which from the IDE, my understanding is that JetBrains had a lot to do with it so they are probably connected.
- Compile times seem pretty fast.
- Errors seem clear, haven't been as stumped as I'd expected with a new language.
- Greytext types that are inferred are super useful. I do wonder how I'd do if the IDE didn't tell me what the types were. But it basically means you get all the benefits of type annotation without having to write out the types.
- The style of using a lot of filter/map/reduce makes my code more terse, but the greytext hints keep it easy to understand.
- Great sugars. No need to add getters and setters for every member. Likewise it seems to change the calls to old Java lib getters and setters. Data classes can be short and sweet. One-liner functions in-line for simple stuff to keep simple stuff short.
- Can still do whatever you want with Java libs. Unit testing for instance works much the same.
- Ecosystem has moved nicely with Kotlin. Ktor and Ebean seem to be on board and pretty mature.
- Null safety built in makes it clear where you need to do something about it.
Actually the strong-type-inference plus greytext thing is one part of Kotlin where I'm not sure what to think about it.
When I first saw Kotlin examples on the internet with all the "it.something" I was "What is going on there?!? What is that supposed to do".
Then the first time I tried writing Kotlin myself everything became super clear due to that Greytext shown in IntelliJ. However 80% of the time I'm looking at code is not in an IDE. It's either on code reviews or in the browser (github, internal code browsers, etc). All the information is not available there, and one has to be aware again what the implicit types will be.
The challenge certainly also exists in other langues with type inference (auto in C++, var in Java/C#, inference in Rust, etc), but for some reason I found it worse in Kotlin. Maybe due to the commonly used methods which take a closure/interface as last parameter, and and the fancy builders.
The good news is there's GitHub integration in the IDE so you can review code with type inference hints. And adding/removing the types (converting between the inlined hints and real text) is a hotkey away. I tend to treat it as a matter of experience and style, when to specify the types explicitly vs not. Quickly disabling the hints is also reachable via hotkeys and then it is often apparent when a type isn't immediately obvious.
Definitely my favorite language currently, and extremely well-suited for server-side, it's certainly not just about Android.
KotlinJS feels so much more natural, safer and faster to write (in IntelliJ especially) than writing plain JS does.
Thanks for your input
However, it's fair to make a distinction between the slowly evolving Android runtime and the JVM. Java language features are catching up with Kotlin, and might even surpass it (I believe pattern matching might land in Java sooner than in Kotlin). Also Kotlin might get stuck for a while when big breaking changes finally come to Java (like Valhalla). I understand why some companies/teams think it's not worth it.
myFun(someVar, { it.something() })
it can be written like myFun(someVar) {
it.something()
}
or if no parameters to the function other than the lambda like myFun {
it.something()
}
making the function almost look and behave like a language keyword. I also use extension-functions a lot. Especially for libraries or legacy-java code we wont touch. Where I work we now use Kotlin for all new backend code. And we don't do any Android.So you can partially specialize, and then the lambda gets the already allocated/opened resource, thus acting as region/arena resource allocator.
And you can combine it with currying to apply the concept to multiple kind of parameters.
I loved Grape for single-file scripts. Does any language have similar single-file dependency manager? I guess Go, but then, you have to compile Go, so it might not be as useful, because you distribute binaries anyways.
Depends on what you call pattern matching. Kotlin had pattern matching from day one, but it's just one level, Java might have it recursive by java 19
Guest languages relevance always fades away as the platform language improves and the FFI gets out of touch with that old version of the language.
C18 on UNIX vs C++, JavaScript vs Typescript (see private members), and when time comes inline classes/reiffed generics/SIMD types vs being able to target both Android and JVM on Kotlin's case.
But in reality, it's not the same thing, it's not the same time, not the same market environment.
Kotlin can succeed where others failed before because just about everything about it is incomparable with sorts like Beanshell.
In reality, while the differences are minor, they are the same thing. Time fades away, and market dynamics operate the same as they did 10,20..100 years ago.
The hubris is in using absolute statements ("platform languages always win") instead of being a little bit more humble with their projections. Old men should know better that history rarely unfolds as expected.
Kotlin has made too many promises that it can't keep.
ISO C++ has kept upgrading the support regarding ISO C libraries, as long as new grammar features aren't required.
Even ISO C++20 has finally added support for structure member initialisation, it is just a subset of what is possible in C.
So while UNIX vendors are free to use all C features, due to their symbiotic relationship, ISO C++ applications can only safely compile C89 code.
No full structure member initialisation, restrict, VLA,...
Kotlin Bootcamp for Programmers[0]
Developing Android Apps with Kotlin[1]
There's also an advanced android development course which is a follow up which I am going through now.
[0] https://www.udacity.com/course/developing-android-apps-with-...
[1] https://www.udacity.com/course/developing-android-apps-with-...
Google has it's own way of doing things - boilerplate, overengineered and full of ugly practices. Anyone will be better of learning from a source that isn't a bunch of interns that got thrown into the Android team.
Even the samples use Java 7 style code when comparing for terseness.
All the Jetbrains IDEs have that. When they enabled it, I was annoyed for a while (not enough to turn them off), but now I love them :) Especially, as you mention, for LINQ (in C#, essentially chained operations like map/reduce/etc.)
I like WebStorm so much better. The inline parameter names on function calls, the local history, the awesome diff tool, the refactoring capabilities (even for Javascript). This makes is well worth the money. Also, I like IntelliJ's perpetual fallback license policy. Feels very fair to me.
It required a huge outcry, but they did the right thing in the end :)
That's nothing. You should have been here when they used to let us buy the tools :-)
But, at least at my company, we always tend to hit some corner case that the documentation doesn't cover or some bug that isn't searchable because let's face it probably < 1% of people using a Java ORM is using Ebean compared to JPA or Hibernate.
In the end it's left me longing for a proper JPA implementation.
[0] https://ebean.io/docs/setup/activerecord
I've been primarily writing Kotlin for the last.. uhh, 3-4 years I guess. TS and VSCode pairing is good, but Kotlin + IntelliJ is both more faster and accurate in terms of knowing what you want and when you want it. Autocomplete, code generation, refactoring, moving works so good it is a huge productivity boost. And the "peeking" at types (the implied type is shown in a small gray box) lets you keep your code clean but very readable.
I can't tell you how many times it has autocompleted FooClass.Companion.functionName() for me and then immediately suggested that I should remove the Companion part. "Ya think?"
The performance also doesn't seem that awesome for me. It doesn't require a very large file before it starts taking several seconds to highlight and analyze it. Granted, I haven't upgraded to 1.4 yet, which supposedly improves performance.
It's very hard to pin point, but if you're developing a large project, you'll notice when autocomplete works 100% of the time (IntelliJ), and 93% of the time (VSCode).
Exactly this. You notice the "smoothness" is off, which when accumulated burns your context faster and kills your flow.
Really looking forward to seeing what happens with Kotlin native. Compile times were pretty bad last I tried it but I’d give it another go if they improved those.
Or use GraalVM native-image to AOT compile Kotlin/JVM to a standalone binary. That gets you same user-visible outcomes more or less, but you can then use all JVM libs, not just Kotlin libs.
If anyone reading this thinks about using Kotlin and has more positive views towards FP, there's this project to bridge the gap somewhat
The problem isn't that the language features Scala introduces are objectively bad. It's that they're in constant tension with the underlying platform. On the one side, you have Scala's FP features harming interop with other JVM languages. On the other hand, you have Scala's dependencies on the Java APIs and type system hindering its efforts to be more functional, and making a lot of things feel way more complicated and tricky to use properly than they do in, say, Haskell.
Kotlin isn't everything I'd want in an ideal world, but it's everything I'm comfortable asking for in the real world.
However, most people who choose Kotlin probably don't want to do "fully fledged" FP anyways and prefer to take the faster compile times etc. over it.
I like the Scala side better though. ;)
What they predominantly do is help library author's to easily re-use and combine other libraries and provide them to their users while allowing for much greater flexibility than without them.
So yeah, that's not a day-to-day problem of a system engineer (which I and most developers are) but they prevent a lot of these problems from even existing in the beginning.
In the end, both are very useful in a different way and I don't like to work in languages that are missing either of them.
To those who are using Arrow- why not Scala? Is it just because Scala has too much cruft? The only thing Kotlin has over Scala (AFAIK) is coroutines, which, honestly- I don't even love. They're very awkward to use and require unchecked exceptions for control-flow (and therefore have convention-based rules around using them).
It's the same for Scala and Haskell, which is why Scala is sometimes called Haskellator - I still would start a project in Scala because I'm more familiar with it.
[1]: https://github.com/holgerbrandl/krangl
[2]: https://github.com/mipt-npm/kmath
[3]: https://github.com/lessthanoptimal/ejml/tree/SNAPSHOT/main/e...
[4]: https://github.com/JetBrains/lets-plot-kotlin/
I've been in a few conservative backend projects in the last year where they were stubbornly insisting on Java. I've managed to convince a few on a path to Kotlin.
For those not familiar with the situation. With Spring 5 & Spring Boot 2, Spring started supporting Kotlin properly (i.e. 2 years ago). It worked fine before that but now Spring comes bundled with a lot of Kotlin extension functions that bridge the gap to idiomatic Kotlin. E.g. all the reactive stuff that Spring has you can (and IMHO should as it simplifies things a lot) do using kotlin co-routines. Things like Flows, suspend functions, etc. all just work seamlessly with Spring's Flux.
Also the documentation is now updated with kotlin code examples and increasingly it seems a lot of features are more Kotlin than Java centric.
If you don't need Spring, Ktor is emerging as a nice lightweight alternative. It's more of a express.js/ sinatra style framework. You can actually use Spring in a similar way with the bundled Kotlin router DSL but not everybody does that.
What do you mean exactly? I feel like Kotlin's brevity is what actually makes it a lot more readable than Java. With Java there's just often so much noise and fluff that doesn't actually mean much, obscuring what the program actually does. Could just be my personal preference, but I feel like in general I have an easier time understanding terse, dense code rather than spacious, verbose code.
I should say, though, that I am by no means an expert Kotlin developer; maybe I just have to get used to idiomatic Kotlin.
Even better, in the latest IntelliJ you can create new inspections from structural search, which is an AST based matching system. So you have a lot of flexibility to make your own lints and warnings without needing to write plugins.
However, I think there's a more general issue here, which is that if you don't trust your team to write tasteful code, linters will be of limited use. It may be better to invest in more rigorous code reviews, trainings, style guidance, mentoring etc. I've spent five years managing technical teams using Kotlin (yep, early adopter!) and found most of them could handle it just fine. A little training goes a long way. The worst problems came from developers creating overly complex abstractions, not playing code golf.
Developers look at their freshly written code, marvel at how succinct it is and then pat themselves on the back for being so clever. "It's just one line and I read it. Boom! Readable!". A few months later, another developer comes to look at the code and has to spend 10x more time parsing each character in that statement before they can even understand the logic behind it.
Brevity might be a kind of "vanity metric" when it comes readability.
As for typescript, it's a nice step up from javascript but IMHO more of a gateway drug to other languages (like Kotlin).
Although I must admit that I wouldn't use TypeScript in the backend for the projects we work one (but I do for my personal projects).
Can u elaborate on that? Why is TypeScript not suited for some projects?
We also follow a domain-driven design approach for which we not yet have found a good way to implement in TypeScript (at least not on the "tactical" level).
Edit: Also, people don't grok asynchronicity ;)
Code will be mostly read, not written, so if something will make a junior (or in some cases even seasoned) dev scratch their head to be understood, it is best avoided.
EG Often I prefer writing an "if != null else" instead of chaining takeIf{}s.
I love those porting back to Java projects after the pixie dust fades away.
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 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
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".
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.
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.
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.
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.
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.
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.
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".
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.
Async/suspend functions are one color, and "normal" functions are another.
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.
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.
ART has also long had hooks for native allocations to influence GC pressure ( https://android.googlesource.com/platform/art/+/987ccff ) , which have improved to become automatic via malloc hooks & use phantom references for cleanup ( https://www.youtube.com/watch?v=7_caITSjk1k )
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)
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.
Or switch to something else like ChromeOS or Fuchsia, both with zero dependencies on anything Java related, including Kotlin.
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.
if (p is Point(x,y)){
//p : Point, x: int, y: int
}
or hell, adopt any other pattern matching syntax.
"Either they adopt the java syntax or are missing features" seems like a false dilemma to me.I work reasonably comfortably in Java (largely due to lombok - thanks!) but keep an eye on Kotlin and... well, I much prefer the Kotlin syntax here.
I'm sure in the 5% case changing variable names is useful, but in the 95% case it's just noise.
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".
data class Point(val x: Int, val y: Int)
// Later on...
if (p is Point) {
let (x, y) = p
// x and y are of type Int
}
That Kotlin has, already, now? if (p instanceof Point(0, 0)) {
// handle origin
} else if (p instance of Point(x, y)) {
// ...
}
and it will get even more complex with matching on nested types (e.g. `if (r instance of Rectangle(Point(0, 0), Point(1, 1))) { ... }).This will be much nicer once it starts working with `switch` expressions too.
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?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.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.
[0] https://download.clojure.org/papers/clojure-hopl-iv-final.pd... p26
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.
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 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.
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.
Looks to me like a valid strategy.
Too many recurring memories from Borland of yore with Delphi, when I see how JetBrains is trying to push Kotlin.
Given that you champion so many niche (and often commercial) languages/platforms with 1/1000th the devs and reach, isn't this a little contradictory?
>and as proven by Kotlin/Native, their expertise is really just making IDEs.
What exactly did "Kotlin/Native" has proven and in what way?
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.
But even just behaviorally it doesn't pretend to be OS agnostic at all. Setting thread priorities isn't even abstracted, it's just "uses the Linux values for this" https://developer.android.com/reference/android/os/Process#s...
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.
Disclaimer: I have never used Kotlin. I use Scala.
I respect your knowledge and breadth of experience, but your biases are apparent.
Yes I don't hide what I think out of political correctness, it is up to the receivers to deal with it.
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!
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.
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. ;)
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.
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.
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.
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.
Eclipse and VSCode plugins tend to be a bit behind, and good luck for other IDEs or editors.
https://blog.jetbrains.com/kotlin/2011/08/why-jetbrains-need...
>The next thing is also fairly straightforward: we expect Kotlin to drive the sales of IntelliJ IDEA.
As for community edition, try to debug Kotlin/Native with it.
Objective-C and Swift runtimes are also owned by Apple.
Not the same kind of comparison.
Everyone else puts a disclaimer on HN. You Oracle people are not special.
Edit: I know I am getting severely downvoted for this. But there are some Oracle shills around here.
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.
https://hn.algolia.com/?dateRange=all&page=0&prefix=true&sor...
https://hn.algolia.com/?sort=byDate&dateRange=all&type=comme...
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'.
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.
https://blog.jetbrains.com/kotlin/2020/08/kotlin-1-4-release...
It's got more detail and is more canonical.
I've been looking at multiplatform development recently and maintain a few oss projects on github that are now multiplatform. The build tools are getting there. The multiplatform gradle plugin has improved a lot over the last year. Generally you can get stuff working pretty easily. If you need to target IOS and Android, it's worth a look. Also if you want to share some code with browsers, it can do that too.
The main issues is with gaps in functionality. E.g. kotlinx datetime just reached 0.1. There were a few third party alternatives but if you needed dates, not having a usable datetime library is a bit annoying. That's just one example. When stuff is missing, you can actually fix it yourself. But of course that ends up being quite a bit of work.
I think for e.g. command line development on Linux or WASM development for browsers, the native compiler is not that great yet. They just started working on WASM only a few weeks ago and posix and Kotlin have not had a lot of attention. This is also an issue when using kotlin-js with node.js; they've just not done the work to expose all of the built in node.js stuff to Kotlin yet. On browsers you get a smoother experience with kotlin-js. Of course people doing stuff on servers can use the jvm and that's why there's just less attention going towards native on that front.
So, wouldn't recommend it for IOT just yet unless you are willing to deal with what is likely to be a rough experience and some gaps in functionality.
The big next pieces are finalizing the transition to the new compiler backend and improving the multiplatform library ecosystem. They have alpha versions of the new compilers currently but they are not ready yet. I also expect there will be lots of activity with both Jetbrains and others releasing multiplatform libraries. I've actually worked on a few of those and would love to see this get traction.
OTOH Oracle people seem to always focus on the platform issues - green threads is the next big thing, but it doesn't actually affect 99% of developers since Java's threading model is just fine for most business applications.
Yet things like missing ability to reasonably express non-nullability (and the resulting NPEs) hit me every single day, but for Oracle it's apparently not an interesting enough to work on.
Oracle are improving the Java language, but of course Kotlin could go much faster as a greenfield project with no community to involve or please. It's got a long way to go to match Kotlin. That said, Kotlin the language is now stable for quite some time and isn't really changing, so it's a relatively static target.
1) As I understand green threads will not require vastly different programming model (no colored functions). So my code can stay mostly the same as it is.
2) My microservices are working just fine now, without performance/scalability issues (certainly nothing related to thread count limit) so why would they turn into tech debt?
> That said, Kotlin the language is now stable for quite some time and isn't really changing, so it's a relatively static target.
Yes, but Java is not moving towards it in some respects at all. There's no effort to tackle the nullability problem for example.
By tech debt I mean, it will become code that is needlessly complex and hard to maintain for what it does and thus become a candidate for simplifications and refactorings. I didn't mean it'll stop working.
Let's assume typical spring microservice - controller layer, service layer, perhaps some persistence or integration with other microservices.
What parts of such microservice will become harder to maintain compared to Loom variant?
Those types of applications are leagues harder to maintain compared to a virtual thread model.
However, lots of people don't write code that is just HTTP servers ("microservices"). Also, consider that when it gets easier to write server frameworks there'll be more competition and they'll move faster. So maybe Spring Boot won't seem so attractive in future as someone will have developed something better.
As the schism grows, library authors get faced with the decision how much they can actually use from the underlying platform.
* https://checkerframework.org/
* https://github.com/uber/NullAwayAh, that is what Google is doing for them.
Isnt the whole selling point for Kotlin, is that it is a JVM hosted languages, that give you access to all Java Libraries, framework and tools .. but purportedly .. is an easier, nicer , more language language compared to Java, Scala or the other JVM languages
Why go elsewhere, why go native, or develop their own VM ? Any improvement in the JVM benefits Kotlin, correct or am I missing something ?
Could they have done a SubstrateVM/GraalVM competitor instead? Yeah probably, but that's a very different project to adding another backend to Kotlin. Given they already decided to make Kotlin "multi-platform" (i.e. js backend) instead of making Java more portable, it then made sense to go the whole way.
JetBrains also developed TeaVM and arguably it'd have been better to just invest in JVM related tooling, and keep Kotlin as a JVM language. But I think they like the idea of it being its own ecosystem. Who wouldn't, in their position?
You mean the Java programming language, or the Java Virtual Machine?
The Python and Lua interpreters are written in C. V8 is written in C++, SpiderMonkey in C/C++. The Rust compiler backend is LLVM, written in C++. The GNAT Ada compiler is powered by GCC, written in C. So what? These implementations work fine.
Directly competing with the JVM makes little sense. Countless millions of dollars of effort have been poured into OpenJDK.
Your list was a bit cherry picked, GNAT frontend is Ada and other Ada compilers are fully bootstrapped.
And GCC has been C++ for quite some time as well.
Plus There are JVMs like JikesRVM and GraalVM, 100% Java.
JVM is fine piece of engineering and Kotlin devs have no problem with it.
Somehow those Kotlin devs have missed the boat that JVMs implementations have between 80% and 100% Java code, depending on which implementation from the top 10 JVMs one is talking about.
The JVM is a specific product. When people criticize Java, they are almost always only referring to the language called "Java".
JVM does not exist without the code written in Java that encompasses between 80% to 100%, depending on the implementation.
Maybe those worshiping Kotlin should take some lessons in JVM implementations, before bashing the infrastructure that made Kotlin possible.
1. The first JVM was surely not written in Java. Therefore JVM != Java
2. A JVM can be written in any language. Therefore JVM != Java
You could write a JVM in brainfuck if you wanted to. That doesn't mean Kotlin isn't a much more sane language than brainfuck.
I have used Kotlin quite a bit. In particular, I've been working on a multiplatform project recently which definitely have helped me learn about some of the less developed parts of the language.
Long ago, I used to do a lot of Java and I liked it a lot (having worked at Sun back around 2000 was certainly part of the reason). Kotlin, in my opinion, is a better Java. It does a pretty good job of providing a nice syntax for it, and these benefits are the first things that are explained in beginners tutorials to Kotlin.
But, it doesn't really do anything new. There are so many things it could do to fix long-standing problems with Java, which Jetbrains refuse to implement due to the fact that the implementation will not be natural to the JVM.
An obvious example is generic functions, or multimethods. This was discussed on the forums, but quickly dismissed with one of the main reasons being that it would have to introduce a new dispatch mechanism and so wouldn't be natural on the JVM. This argument has been made to dismiss many suggested features.
Another reason Jetbrains uses dismiss suggestions is that the new feature would make the language more complicated and difficult to learn. The refusal to implement some kind of macro facility falls into this category.
At the same time, this position leads to truly bizarre language behaviour such as the strange behaviour where declaring a function inline changes the semantics of the code.
This insistence that the JVM dictate the features makes even less sense since they also have native as well as JS code generators.
The only unique Kotlin feature that I can think of which is not a result of the JVM is their support for suspending functions, which is used to implement their async framework. The problem here is that it semantics can be really confusing, and can in fact lead to deadlocks if you have a library the needs to be exposed to Java which internally is implemented using suspending functions. If these functions are then called by Kotlin code which itself use suspending functions, you can end up with really strange behaviour.
What's New in Kotlin 1.4: https://kotlinlang.org/docs/reference/whatsnew14.html