Because the impression I get is that Kotlin is a strict improvement along every dimension. But as an outsider, I'm not sure if I"m just being blinded by hype.
Because the impression I get is that Kotlin is a strict improvement along every dimension. But as an outsider, I'm not sure if I"m just being blinded by hype.
* No checked exceptions destroying lambda expressions and leading to architecture problems (since exceptions are oft not used like the inventors of checked exceptions assumed).
* Functions are real first class citizens and don't need artificial interfaces.
* Named parameters with default arguments are very practical.
* `name: Type` is a better fit for type inference than `Type name`.
* Null-safety helps to avoid lots of bugs.
* The type system with `Any` as a unified root and `Unit` instead of the special case `void` makes programming with generics much easier.
* Constructors are always lean, not only for data classes (record in Java 14).
* Most things are expressions, so you can write `val a = if(cond) 1 else 99`.
* Extension functions and operator functions can be used to write simple to use and elegant APIs.
So at least for me Kotlin is definitive the better Java and I wouldn't start a new project with Java, if I could use Kotlin instead.* No checked exceptions destroying lambda expressions and leading to architecture problems (since exceptions are oft not used like the inventors of checked exceptions assumed).
* Functions are real first class citizens and don't need artificial interfaces.
* Named parameters with default arguments are very practical.
* `name: Type` is a better fit for type inference than `Type name`.
* Null-safety helps to avoid lots of bugs.
* The type system with `Any` as a unified root and `Unit` instead of the special case `void` makes programming with generics much easier.
* Constructors are always lean, not only for data classes (record in Java 14).
* Most things are expressions, so you can write `val a = if(cond) 1 else 99`.
* Extension functions and operator functions can be used to write simple to use and elegant APIs.
I personally wouldn't go for anything but Java (on JVM, that is) for anything that isn't a pet project.
As for Valhalla, it remains to be seen how it's usable from Java, let alone anything else. But Kotlin already has a form of value type (inline classes) so perhaps it'll be an extension of that.
One cannot just change their semantics after the fact.
case class Foo(x: Int) extends AnyVal {
def square: Int = x * x
}
val bar: Foo = Foo(5)
println(bar.square) // => 25
Compiles down to (the moral equivalent of) object Foo {
def square(x: Int): Int = x * x
}
val bar: Int = 5
println(Foo.square(bar)) // => 25
If the inner value (x, in this case) can be stack-allocated or stored in registers then `Foo(x): Foo` will as well. `Foo(x): Bar` (where Bar is a supertype of Foo) will be autoboxed, but that also applies to primitive types (`5: Any` becomes a java.lang.Integer in memory). inline class { ... ]
Which is guaranteed to be always stack-allocated or stored in registers, again you cannot retrofit semantics, specially when passing those classes to binary libraries.There is also precedence for this, Scala 2.12 changed the encoding of lambdas from anonymous classes to Java 8's invokedynamic.
Another huge advantage Kotlin has over Scala is tooling, which is basically all thanks to an IDE company creating the language. Tooling will never fall behind because they are in the business of selling tools.
(You could say the same thing about Sun/Oracle...risks all around.)
Not sure I'd agree with this. Kotlin's ties to JetBrains means that you're basically hosed if you don't use IntelliJ. Scala's tooling works pretty much everywhere (LSP/Metals, ENSIME, IntelliJ, Eclipse/Scala-IDE).
[1] https://medium.com/@fommil/hide-your-real-name-in-open-sourc...
Scala's tooling also pretty much sucks everywhere (interestingly the least sucking IDE for Scala is guess what ... Intellij!)
In your opinion.
Personally I almost get depressed when I have to switch from Emacs+Metals to Android Studio for Kotlin stuff.
The parts where IntelliJ has always fallen down on Scala seem to be precisely the parts that are missing from Kotlin. I can't help feeling that the JetBrains team just "doesn't get" higher-kinded types at all. Which is a shame, because there is a lot of good stuff in Kotlin otherwise.
As far as JetBrains, I am big fan, I have a license for R# that I gladly pay for, but JetBrains is just one company whose core set of products are rapidly being encroached upon by free alternatives.
Jetbrains is even lagging behind, look at vscode remote capabilities which is way ahead jetbrains remote features.
Best of all, I can use Java in any Java IDE.
Needs additional configuration for what the others do out of the box, like Javadoc tooltips.
Requires ten finger shortcuts.
It is also the only Java IDE unable to do mixed language debugging, Java/C/C++.
This has been true for almost two decades now - Eclipse first shipped in 2001, and it competes directly against IntelliJ, which was JetBrains' main product at the time.
And yet, they're still around.
It's being maintained. A new version (3 iirc) is about to come out. But it's not a hot bed of innovation.
I think Kotlin now already has a lot more mindshare and corporate interest behind it than Groovy ever did.
Those of us that are part of the Java world since the early days, have been through this multiple times.
Right, history repeats itself all the time ... until it doesn't. 10 years ago is not now, Kotlin is not Groovy ...
Just like C on UNIX, JavaScript on the browser, ....
The hype curve is definitely in the past, but Groovy is living on quite well as a small but viable option in the plateau of productivity. In some ways that is more important because while in the hype phase it is really hard to judge the true value of a technology. The true value emerges when the hype is over.
The problem is, there isn't really a better scripting option for the JVM. While in theory lots of JVM languages (JRuby, Jython ... etc) could fill that gap, they all have ugly impedance mismatches which Groovy doesn't, so companies continue to deploy it as a scripting and DSL implementation still. I tried to substitute Kotlin for a bit and went back to Groovy because Kotlin still lacks standard scripting constructs such map and list literals etc.
If you’re already familiar with OO languages and their standard coding patterns, then there’s little reason to use Java over it.
To clarify, for the Kotlin / Java users out there that might not get what I mean: the syntax for classes and constructors and default constructors and all can be very confusing when reading Kotlin compared to C#, Java or Python, since the constructor and the class declaration are halfway merged.
Please, distinguish what Scala has over kotlin separately than what cats/scalaz has over arrow. You will be surprised to see how little the list is.
Real immutable collections (might be available in a third-party library for Kotlin, but not used in the standard library or any of the ecosystem)
Well-behaved option/maybe type (arrow implements one, but it's not used in the standard library)
Either type used in the standard library where it makes sense (arrow implements one)
First-class (monadic) comprehensions in which the language behaves as normal (arrow makes an impressive effort, but it has rough edges from not being part of the language, and its implementation inherently relies on capturing pieces of imperative execution, so you can't rely on it for monads that do control flow e.g. a backtracking/nondeterminism monad).
Practical way to implement typeclasses for third-party types, that will be understood correctly by the whole ecosystem (IDEs/debuggers/etc.) Together with the above this means you can enable comprehensions for any standard library or third-party type for which they make sense, not just libraries that were built on top of arrow (e.g. standard collections, third-party database libraries, types from the Java or Android standard libraries). Arrow's annotation processing is a poor substitute for being able to do this in a first-class way, and even if it were built in, the typeclasses are a lot more cumbersome at the point of use.
Practical way to write tiny, composable functions that rely on HKT/typeclasses. In Kotlin if you want to write a one-liner you still have to cart the typeclass instance around, which might seem trivial but is actually a huge barrier to working in high functional style, where you'd write hundreds of tiny combinators that each do one simple but really generic thing.
Monad implementation for the standard way of representing presence/absence, the standard way of representing async, etc. Even with annotation processing, it's impossible to ever implement a monad instance for Kotlin's nullable types (because they're not well-behaved).
Iteratees or equivalent - a way to represent possibly-async transformation pipelines such that even the middle of a pipeline can be a well-behaved, reusable value that we can use a lot of general-purpose functions on.
Record types (relying on Shapeless) and a way to convert back and forth between case/data classes and a generic representation of them - fulfills a similar use case to "compile-time reflection". This really unlocks a lot of functional power when you combine it with applicative / monadic traversals of those generic representations - it lets you walk an object graph, doing something effectful at each node, in a completely safe, managed way.
Recursion-schemes style traversals - representing different kinds of recursion as composable values. This makes it a lot more practical to do things like tree transformations in a safe way, because it becomes ok to have 20 subtly different types of tree representing different intermediate stages of your operation.
Kind polymorphism (relies on kind-projector in Scala which has similar limitations to Arrow) - makes the above a lot more effective, as you can write functions that do the right things for generic and non-generic trees (for example).
The first half of this is more a matter of degree than of kind, because an ecosystem is more than a language. An imaginary Kotlin ecosystem in which everyone used immutable collections and everyone used arrow optionals instead of nullable types might approach the usability of Scala on this front. But the Kotlin ecosystem that actually exists does not operate this way - and, crucially, there's no way to interoperate between working this way and not. Scala was able to overcome this barrier by having implicit conversions and good typeclasses, so even if you have to use a third-party library that doesn't follow functional conventions, you can still enable functional operations for it. Kotlin can't do that; extension methods don't allow the types they're attached to to implement interfaces, so the only way to treat a third-party type as having some functional support is to plumb a typeclass instance for it around manually as arrow does.
And beyond that, trivial inconveniences matter. It's possible to write a well-behaved Either type in C++, but no-one uses them because it imposes so much code overhead that it's not worth it. Ultimately Greenspun's law applies - you can implement any language in any other one - but at the point where you're working in what's effectively a Scala interpreter written in Kotlin (which Arrow is halfway to being), you're gaining very little of Kotlin's benefits (in terms of tooling, ecosystem and so on).
And the things in the second half are more fundamental. Arrow is an impressive effort in working around the limitations of not having HKT, but it can only go so far; at some point you need real HKT in your language. (It's the same story in Scala one level higher - the things you can do with kind-projector are really impressive, but they're also no substitute for using a language with real kind polymorphism). And if you want to actually unlock the power of functional programming, it has to be practical to avoid using anything that breaks the rules of the language - reflection, bytecode manipulation, annotation processing, macros - and for that you need an equivalent of Shapeless (or Frunk in Rust), or ideally a proper record system.
I'd love to be optimistic about Kotlin - there's a lot that it cleans up - and certainly I hope that the language will eventually adopt HKT. But even then, the ad-hoc approaches of the language's early design will always be a millstone around its neck. I mean, fundamentally, Kotlin collections are mutable and nullable types are ill-behaved, and I can't see the ecosystem/culture ever managing to go through a wholesale conversion to using immutability and proper optionals (contrast this with Scala where mutable collections and null exist but you'll never see them in a mainstream Scala library). And that alone is always going to make it less pleasant to work with than Scala.
Outside of Android I wouldn't choose Kotlin.
For back-end service/API type things in an enterprise setting, Kotlin is a good value proposition. There's also probably some truth to the idea that one reason modern Java is adding these things is because of Kotlin's existence.
Lambdas can't handle checked exceptions, which are the most common exceptions in the system.
There is no way to extend Stream with your own methods.
Still 8 primitive types to wrestle with.
Just to name a few issues. And there are lots and lots more.
The language is simply not extensible enough to write anything elegantly.
() -> {
try {
// do work
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
I also agree with Goetz that extension functions aren't something we need.Regarding extension methods, while they are nice, with import static it just a matter where the extended type comes, big deal.
And from experience in .NET world, hunting them down isn't always fun, even if they are just Ctrl+F12 away.
You can do exactly the same thing that Kotlin would do for you and just rethrow them as runtime exceptions. It's one extra wrapper call; not great, but not a huge overhead either.
> There is no way to extend Stream with your own methods.
That's just syntax sugar; all it's actually doing is calling a static method, which you can still do in Java.
> Still 8 primitive types to wrestle with.
You can just ignore them and use the object versions everywhere, and then it's not a problem.
There are a bunch of irritating warts in Java, but irritating warts alone are not worth switching language over.
i kinda get how this is safer, but clients can just call optionalRef.get() without checking, and boom there goes the safety. compiler warnings be damned.
You could also do this in Kotlin and boom there goes the safety:
fn nonNull(): String {
val s: String? = null
return !!s
}Some features like named parameters or null checking might probably never make it to Java.
There is a nice talk about this that compares Kotlin to what will be in Java 19:
Really, I don't get this claim Kotlin will lack Java features. Most big Java upgrades these days are at the VM level. Kotlin gets those mostly for free, once they choose to upgrade to newer bytecode features (which they are slow at doing admittedly, but that's because they're in the middle of a compiler rewrite).
It also means that Kotlin on Android cannot just consume any random Java library, only those that are compatible with Android Java flavour of the month.
https://dev.to/martinhaeusler/why-i-stopped-using-coroutines...
https://dev.to/domnikl/kotlin-coroutines-and-javafx-threads-...
https://blog.danlew.net/2020/01/28/coroutines-and-java-synch...
Scala also is a different beast (the one I prefer personally). I can understand people not choosing Scala if they're not into FP and are afraid to be unable to recruit Scala developers.
But Kotlin being some sort of "improved Java", the philosophy stays the same, Java developers can seamlessly switch to Kotlin... The benefit of picking Java over Kotlin is pretty slim.
There are good, explainable reasons why people hate Java and Javascript. Fundamentally, one can argue that they are very nice and solid languages and all those complains aren't warranted. On the other hand if you look at them differently and treat them as low-level, sorta "assembly" languages for their respective platforms, then probably you would find out that Clojure is an amazing tool, because it can perfectly be hosted on both of them.
And given all the good design decisions that went into Clojure, one might argue that it's almost always better to choose Clojure instead of Java.
Anyway, nowadays you wouldn't see me making the same statements anymore.
My first issue appeared when I was maintaining an Android app written in Java. I needed an library for some functionality. The only maintained ones were kotlin-libs. But interoperability, right? I didn't hesitated to include it. There is no way to use or extend functionality with typealiases in your java code.
IntelliJ can compile Kotlin into Java and it is easily accessible. But there is no adb debugger for kotlin.
Null Safety is just overhead imho. I know when it is appropriate or neccessary to check for null, otherwise i can get rid of it. And its more easily grep-pable the Java way.
Writing Kotlin is not so fluent as one would guess, the tooling only fools you, that it is. You can easily make use of actions like typing pfi (extends to public final int) for java aswell. But when your property changes from nullsafe to nullable, you need to rewrtiging eeevverything.
Additionally, i do not like the implicit type on member property declarations used by almost anybody. The benefit of typing less boilerplate becomes annoying when reading sources outside your ide.
Boilerplate in my opinion is code i need to write by myself. When it is generated by any IDE, i do not bother about it. We are so familiar with Java that we can abstract this boilerplate when reading sources.
Spelling Kotlin to somebody via telephone is also strange for me.
I stopped promoting Kotlin as a Java killer. Code style is too different between different developers.
And why are we creating the same libraries once again?
Not having null safety seems like overhead to me.
> I know when it is appropriate or neccessary to check for null, otherwise i can get rid of it.
How do you know? Do you have the entire code base in your head. What about when someone new works on the project?
> And its more easily grep-pable the Java way.
What does this mean?
That said, Kotlin is awesome language with awesome tooling. I don't think that it'll go anywhere since Google declared it as a preferred Android language. So you won't make a wrong choice, it's just a matter of personal preferences. I'm more of old guy who's not afraid of writing XML and repetitive code and don't like all that modern functional one-liners.
If you mean getting in the way of writing reliable software.
There are still resources available for Kotlin + Android development but non Android resources are very few.
The plus side is because of the First Class Support in Intellij Idea for Kotlin, I can always take Java snippets and have the IDE convert them to Kotlin.
Within ~2 years, native things will hopefully become sufficient, but the state now isn't gloom and doom.
Ofcourse I am banking on resources improving with time.
So now for every problem we need to consider Java + Guest Language idiomatic libraries + alternative build tools + alternative IDE, across the whole corporation.
IMHO, any language features rank incredibly low on the list of reasons you might use a language. Things like how long has the language been popular, how long will the language be popular? How strong is the community around the language, how long will it stay strong? What else can you use the language for? What tools are available, is the tooling in a competitive market? Which of those things is most important to your application?
A lot of those questions can't be answered directly, and have to be guessed at. But in the Kotlin vs Java scenario, the choice is pretty obvious for most applications.
I think the Typescript/Javascript comparison is more apt, and at this point I'm pretty sure that Typescript will win.
There's this misconception that Kotlin is an Android only thing or a JVM only thing. The reality in both Android and server side frameworks is that the big frameworks are all moving towards being Kotlin friendly/ready. Additionally, Kotlin is rapidly moving towards being a proper full stack language with a native compiler (currently in beta), a javascript transpiler, and lots of other tooling maturing. People are already doing cross IOS/Android libraries in Kotlin.
A big advantage of Kotlin over e.g. Scala and other JVM languages that are not Java is that it is designed from the ground up make the transition as seamless as possible. Scala is so far removed from Java that it's generally a completely separate ecosystem with its own libraries, tools, frameworks, idioms, etc. Yes you can use Java stuff but it's generally frowned upon by Scala people.
This is not the case with Kotlin at all. The Android ecosystem started transitioning to Kotlin long before Google recommended that and before Kotlin 1.0 because the pain of having to deal with Java 6/7 just made that development so much better. A few years ago they started endorsing and recommending it and at this point they are clearly deprecating a lot of stuff that they did for Java that can be done better with Kotlin e.g. embracing co-routines over rxjava, adding extension functions and kotlin dsls and designing new features that really only make sense if you use Kotlin. On Android, if you are doing Java, you are working on a legacy code base.
On the server side the same is happening with e.g, Spring, which is basically the dominant server side framework for the JVM. I used Kotlin with Spring Boot 1.x/Spring 4.x, and it was a nice upgrade despite the lack of Kotlin support for it.
With Spring 5 and Spring Boot 2.x they started adding a lot of Kotlin extension functions, co-routine support (which generally makes using their reactive stuff less painful), and there's an experimental project for Kotlin DSL (https://github.com/spring-projects-experimental/spring-fu) to replace the mess of annotations that is currently needed and which reduces the need for reflection, proxies, and other tricks that currently make using Spring with Graal vm hard. Basically, what that means is that if you use Spring in a new project and you are not using Kotlin, you are probably making a mistake because you are missing out on a lot of good stuff. They'll likely not deprecate Java entirely for a long time just because there are a lot of very conservative projects in e.g. banks using Java but if you read between the lines they are basically saying Kotlin is it going forward.
IMHO, the Java language is definitely improving but just not at a pace where it actually keeps up and a lot of the stuff they add is a big compromise compared to what you get in Kotlin. and of course Kotlin is improving as well and a lot of the Java changes (and related JVM changes) also benefit Kotlin.
> This is not the case with Kotlin at all. The Android ecosystem started transitioning to Kotlin long before Google recommended that and before Kotlin 1.0 because the pain of having to deal with Java 6/7 just made that development so much better. A few years ago they started endorsing and recommending it and at this point they are clearly deprecating a lot of stuff that they did for Java that can be done better with Kotlin e.g. embracing co-routines over rxjava, adding extension functions and kotlin dsls and designing new features that really only make sense if you use Kotlin. On Android, if you are doing Java, you are working on a legacy code base.
There's a contradiction between your paragraphs; my experience is that as Kotlin projects mature, they also reach a point where developers frown on Java idioms. I mean fundamentally either the language is different from Java or it isn't; if it is, the transition isn't going to be seamless, and if it isn't, then why use it? The Kotlin community may have been better at being supportive, but the practical experience of making the transition is exactly the same (e.g. I used Spring for my early Scala projects, and found that to be a very nice way of working).
The only ones I can think of are where the language provides a feature that automates some Java boilerplate, so it wouldn't make sense to write things out by hand anymore. Otherwise they're semantically identical languages so the gap isn't big.
IMO there's a contradiction at the heart of Kotlin's positioning. As the quote goes, a language that doesn't affect the way you think about programming, is not worth knowing. If programming Kotlin is just like programming Java, why not just keep programming Java? If you want to switch to Kotlin because it's going to unlock a better way of programming, then that's going to have to mean changing how you program. It may work as a trick to get users on board at the start, but ultimately the language will have to find its own idioms and patterns, or else go the way of CoffeeScript.
Kotlin is being developed primarily by developers based in Russia. Putin relies on geopolitical conflict for consent manufacturing within the country. One of his future antics could turn into a real crisis, where Russia ends up sanctioned and isolated as a result, after a series of tit-for-tat moves, with the corresponding disruption to normal business processes.
Being a Russian product it also carries a risk of one day receiving an update with a payload from Russian secret services, if they find your firm sufficiently interesting. But it's a general consideration with software/hardware from "adversary" countries like China or Russia. The story with Huawei is the same.
But you know, the most aggressive country by far at backdooring systems is the USA. For the vast majority of us who are neither American nor Russian it's all swings and roundabouts.