197 comments

[ 3.8 ms ] story [ 168 ms ] thread
The crux of this is that they're not doing Android stuff, so they have the luxury of using Java 10.
And that is perfectly fine. Java 10 and then 11 and so on will bring a lot of niceties to developers. I switched my projects to 10. Haven’t had much issue. Now I get to use var!
Agreed. Because they had that option to them, they were able to switch back. If they were stuck with Java 7, they may have decided that the niceties of Kotlin were worth more.
TBH, I think Java 10 is strictly inferior to Kotlin even when you have that option. Kotlin on the Java 10 JVM is pretty great.
Roughly half of the complaints are against Kotlin specific features or hazard of mixing Kotlin with Java libraries - I was curious since I only use Java for Android as well and have not shifted to Kotlin.
I've been using Kotlin with Android for over a year. There have been few problems with SDK interoperability. Since I started using Kotlin Google blessed it. The one annoying gotcha was JSON parsing. If the fields on your models are not declared as nullable, they can still be set to null in the JSON which causes a NPE.
I have been using kotlin in prod for over a year now on Android (and I already knew the language beforehand).

I don't see myself writing full time in java again, ever.

Right, but because they were able to use Java 10, a good amount of the pain points that Kotlin was intended to address go away. On Android, you're stuck with Java 7 with one or two Java 8 features, so Kotlin helps out a lot more.
There exist really, really good arguments for the structure of a programming language. Obvious example: I think Perl-as-is-generally-written is line noise. But complaints like "the type comes after the variable name [so that we can consistently define types, including in arguments, without inconsistent syntax like Java is now forced into]"...aren't good. You might not be comfortable with it off the jump; it's more consistent, it reads fine, it improves implicit typing because you don't need special-case syntax, and it should not be bothering you past the first hour with the language.

T! being a little odd is a fair criticism--or would be if it wasn't literally inescapable when working with languages that are, like Java, guilty of Hoare's mistake. For my money they do a better job of it than Scala does, that they address it at all when Java doesn't is admirable, and I think it generally works pretty well. I think Kotlin should make every T! a T? and force you to deal with the null cases, to be honest, but that would probably make the author upset because it'd splat `!!` all over the place.

Companion objects are objects, not special-cased static...things, and are significantly more useful than static methods and fields once you have put in a few seconds of chin-stroking to consider why people as smart as the Kotlin crew would have gone that way. Making useful things out of classes in Java sucks, whereas in other environments (something like Ruby comes to mind--as an example, Sidekiq::Worker provides meta-information to Sidekiq because of the configuration of your job class) it's fluid and natural. Kotlin tries--it's not perfect, but within the bounds of playing-nice-with-Java it tries--to improve that. Treating companion objects as useful things in Kotlin is solid.

And I have no problem writing a program entrypoint from memory, on the rare occasion I have to. Probably because I understand what everything in it actually...does? And I'm not a Kotlin specialist or anything, I just take the time to understand my tools when I use them.

Option/Maybe types are a good idea. I've used Kotlin-specific ones in Kotlin and it was...fine, but the "oh, look at this `let` thing, isn't it so much harder than the Java one?" thing is a head-scratcher. It smells like another case of "I expect things to look like Java so I throw a rod when it doesn't".

Data classes are great. That C# doesn't have them is one of the reasons I dunk on the language so much (along with the `static` mistake, but like Java, they were young and foolish). Closed-by-default classes--meh, whatever. Have that argument if you care that much, but we're a tool-using species, set your linter to complain about closed classes if you really care that much.

Don't get me wrong: I think one is probably wasting one's time to be using Java preferentially in 2018, but use what makes sense to you. Have decent reasons for it, though, and a lot of this seems like "this is different and therefore scary and therefore bad." Like--steep learning curve? Man, I was writing mostly-idiomatic Kotlin that plugged right into Java libraries in a couple hours.

This whole article reads like a weird lazy lament: that changes are hard, seeking new local maxima of correctness and productivity is uncomfortable sometimes, and challenging that discomfort isn't awesome. And maybe Kotlin is worse for the author's particular flavor of code--but, having written a lot of Java and a lot of Kotlin, I really doubt it. Kotlin is spectacular for me specifically because it does not force me into Java's lowest-common-denominator design. It gives me room to be smarter about the stuff I write while still using the often-very-good libraries available through Java on the JVM. I don't get to write as much of it as I'd like, these days...but doing so is consistently fantastic.

EDIT: Actually, while...

steep learning curve does seem laughable.

If you know Java, you can be start writing kotlin after a couple of hours with the kotlin koans.

My main pain point with kotlin is that I generally have a good idea of how my code will look like as bytecode (like this feature will need an intermediate object, so let's use this instead in this very big loop). In kotlin, it is a bit more of an uncharted territory, even with the fantastic 'see bytecode' tool.

I've had the same complaint before, for sure--when writing very perf-conscious, GC-sensitive stuff I still might hop over to Java because I do understand its exact behaviors a little better. But, as you mentioned, the bytecode viewer helps a lot.
I should have mentioned that in both cases, it is a bit of a pipe dream to think you can envision what the compiler will churn out.

Especially with one that is constantly evolving like kotlinc.

Some of the bad practices of 5 years ago have devolved into cargo cults and the compiler can actually handle these cases fine now.

So I guess that this is not that great of a reason to choose either Java or Kotlin.

In both cases, if performances are critical and lacking, you will have to whip out systrace and look at the bytecode.

i agree with your point about the way Kotlin does blocks. the '->' syntax within the block still trips me up a lot. maybe one day i'll be used to it and not have to think about it...
> I think the way they do blocks is odd. I think that the braces should encapsulate the body of the block, not the variable expression as well

I can't find an example of what I imagine you're saying.

Can you link to an example from here the reference docs?

https://kotlinlang.org/docs/reference

I believe they are referring to the lambda syntax: https://kotlinlang.org/docs/reference/lambdas.html

  // Lambdas are code blocks enclosed in curly braces.
  items.fold(0, { 
    // When a lambda has parameters, they go first, followed by '->'
    acc: Int, i: Int -> 
    print("acc = $acc, i = $i, ") 
    val result = acc + i
    println("result = $result")
    // The last expression in a lambda is considered the return value:
    result
  })
Correct. It looks bizarre. Ruby at least sets off the arguments with pipes.
Good and clear summary of Kotlin warts. In the end I couldn't suppress the thought that there was some hidden Polish-Russian rivalry going on ("Kotlin" == "Heinz") ;-)
Heinz is American (and, in the context of the article, a global brand), not Russian.
Sure, it's about the (negative/funny) association. I was recently told about persistent animosity between Poles and Russians; it crossed my mind given JetBrains is a Russian company masquerading as Czech. BTW, I also think that the name "Kotlin" is the worst aspect of the language, especially when you hear how is it pronounced by the authors in Russian. Big plus for language/runtime/transpiler features, big minus for the name.
Kotlin the ketchup raises perfectly positive associations for an average Pole. It's a household name, and a company with a nearly century-long tradition under its belt!

The authors wanted to name it after a Russian island (as a nod to Java); if you browse the names, some other possibilities were Iturup, Urup, Sakhalin, Kolguyev, Paramushir... :) Kotlin ain't so bad, then

I found the transition from Java to Kotlin painless because Android Studio (Intellij) holds your hand all the way. If at first you're unsure of the syntax, you can just write code in Java and convert to Kotlin.

I agree that the null-safety Java interoperability does not work properly if the Java code is not annotated correctly (or you're parsing JSON) but I'd still prefer to have it than not.

I like Kotlin because: * If is an expression and it feels so clean * Functions are first-class (you can pass functions to functions) * Kotlin is less verbose than Java so there is less to read and write * You don't have to write "new" * Constructors are cleaner (you don't have to write (this.a = a) * The map function (on Android we were stuck on Java 7)

I'm unfamiliar with Kotlin in detail. Can you explain "Functions are first-class (you can pass functions to functions)"? Are they more powerful than Java's lambdas?
I think the big use-case is on Android where you're stuck with Java 7 and therefore can't use lambdas.
That used to be the case, but the build tools have supported lambdas for a while now, and it works even on very old devices.

On the other hand, Java 8 classes like java.util.Stream only exist on API 24+ devices. So if you want to support older classes, you can't use the standard stream library.

Ah interesting. Thanks for the info.
Yes, Java lambdas are just syntactic sugar over anonymous classes with a single method IIRC. You must define a full Interface to use when defining the function signature. Kotlin functions are essentially objects that can be passed around, stored in variables, etc. You can also have functions that don’t belong to any class, no need to use static methods for that.
Not exactly, lambdas use invokedynamic which has different performance characteristics when compared to anonymous classes.

See a talk by Brian Goetz - https://www.youtube.com/watch?v=MLksirK9nnE

Great, thank you for the correction. I only knew of what it looked like from an implementation perspective, had no idea things worked differently at runtime.
They're slightly different. Kotlin's compiler does some tricks that Java doesn't do to inline lambdas passed to functions. But Kotlin doesn't currently use Java 8's invokedynamic on the JVM, though they're planning to in the future. Not sure about on Dalvik.
A number of valid points, but I'm not convinced by most of your critique of Kotlin.

Colon between names and types (as in "i: Int") "makes work in Kotlin harder"? Seriously? By as much as having to end lines with semicolons in Java? : ) I understand it's a matter of habit, but how could that possibly make anybody's work hard is beyond me

"I can’t imagine a valid use case for shadowing a method argument."

Arguably this would be better off causing a build-time error, like in Java. But is this such a problem in practice? Do you really keep bumping into it accidentally? Just don't use name shadowing...

"In my opinion, Kotlin’s type system with all these scala-like !, ?, and !! is too complex."

You've listed "all these" already :) All three of them, among which "!" isn't even something you'll ever use yourself. How is it more complex than explicit null checks?

It's also trivial to implement Optional in Kotlin if you think you need it. Thats pretty much all you need: https://github.com/gojuno/koptional/blob/master/koptional/sr...

"Why Kotlin infers from Java T to T! and not to T??"

Probably because not doing that would require putting "!!" or "?" pretty much everywhere you call Java code, even code that you know for certainty won't ever return null - such as Observable.create or every single RxJava operator, for instance.

    Observable
        .fromCallable(something)!!
        .map(String::trim)!!
        .distinctUntilChanged()!!
        .switchMap({ searchPhrase -> handleSearch(searchPhrase, view))}!!  
        .scan(
            initialState ?: DEFAULT_BLANK_STATE,
            {
                full, partial -> full + partial
            })!!
        .doOnNext { logDebug(here) { "Returning new, updated full state:\n$it" } }!!

Etc. That's what it would have to look like if they made it your way.

"In Java, we write the class name with .class suffix:

    Gson gson = new GsonBuilder().registerTypeAdapter(LocalDate.class, new LocalDateAdapter()).create();
[...] in Kotlin, you are forced to write:

    val gson = GsonBuilder().registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()).create()
Which is ugly."

Seriously? :) It's pretty much identical code, with slightly less noise in Kotlin. All the difference is type inference (which you praise at the beginning), and no need for two "new" keywords in Kotlin, at the cost of having to add one ".java" after "::class". The difference is rather subtle, so I honestly fail to see why the former version passes for normal while Kotlin's is suddenly "ugly"...

That GsonBuilder example is also screaming for an extension function like so:

  inline fun <reified T> GsonBuilder.registerTypeAdapter(adapter: Any) = this.registerTypeAdapter(T::class.java, adapter)
Bam, now it'd be:

  val gson = GsonBuilder().registerTypeAdapter<LocalDate>(LocalDateAdapter()).create()
(comment deleted)
I work in Kotlin and Java and have opinions on both. Some feedback...

I disagree about the name shadowing issue. In fact, I wish Kotlin didn't suck so hard and not allow me to ignore those warnings specifically. My primary use for name shadowing is so that I don't use the previous variable. This may be a bit strange, but in highly functional contexts with immutable variables, shadowing a name is reasonable especially as you begin to nest. It's not like Kotlin has a problem reusing/shadowing the "it" var name in nested blocks. Rust makes me very happy with how it handles it and it makes the code quite readable. Something like `val someValue = someValue ?: error("Bad value")` is very reasonable. If anything, you can have reasonable scoping warnings if there appears to be ambiguity, but it should not be across lambda blocks as it is now.

Can't cite type inference in Java if one of its most popular platforms doesn't support it. May be ok for you, not ok for everyone though. We might wish Android would keep up, but in the meantime we have practicality concerns.

I don't think those three nullability sigils make it too complex and has nothing to do with Scala where devs can define their own sigil operators. And Kotlin is ok about inference when the Java code has reasonable nullable/not-nullable annotations. There are a lot of problems with Kotlin's compile-time null checks (namely their insistence on thread safety so a null-checked field can't be reaccessed and assumed null), but "platform types" is the best that can be done within the constraints of existing JVM code.

Having the IDE put ::class.java in there is hardly a reason to go away. That's like saying I'm going back to Kotlin because sometimes in Java I have to type .class if its a type and .getClass() if its a value. The obvious reason for it is that Kotlin classes are supersets of Java ones and have more reflective properties. That and not everything is about the JVM (Kotlin has two other targets). If you can use KClass's, they are preferred.

There are too many articles on why languages like Scala, Go, Rust, etc choose to add the type to the right hand side of parameters/functions for me to re-explain it here.

Your complaints about statics are because how the JVM handles statics, not Kotlin. I appreciate the object approach over JVM statics. Just sucks that you keep having to go back to JVM-land where you are hamstrung. As your apps and library usage grows, you will move further away from the requirements forced upon you by Java and stop complaining about that being the reason you are going back.

The key-value not using a new operator thing is simply because one is defined as a piece of a library and not part of the language. You want them to write a special operator for maps which are not even part of the language (just a class that happens to be part of the stdlib)? Instead of an infix "to" that creates a Pair class? The disappointing part is wanting to extend the language syntax even further.

You wrote:

    fun parseAndInc(number: String?): Int {
        return number?.let { Integer.parseInt(it) }
                    ?.let { it -> it + 1 } ?: 0
    }

 and complained about readability, when I see that and think:

    fun parseAndInc(number: String?) = number?.toInt()?.inc() ?: 0
And I think, not only is that quite readable, but it sure isn't very practical to accept a null number here. Take a peek at the generated bytecode at some point too compared with your Java version. I'm a little concerned that this kind of stuff has you switching languages...if you make bad examples I bet they'll look bad.

In your back-to-Java article you mention data classes with no Java alternative.

Spring is annoying. If you're a Spring shop, and you're ok w/ all the magic, stay in Java. It might be best.

Sorry I typed so much. I have lots of problems with Kotlin too...but I sure don't share s...

I agree about the shadowing. I find in some cases I need to refine a value to a more correct/cleaned/canonical form, but a separate method to establish an all-new scope is too much and would impact clarity. In those cases it's an insidious bug to accidentally be using an old/non-canonical form of something in the following code somewhere, mixed in with the uses of the refined form, just because the name can't be shadowed. It's very hard to spot because both forms seem to "read" correctly in isolation.
Optionally ignoring thread safety seems indefensible -- until you can go full COM and declare your package apartment-threaded, working in a mutable language with uncontrolled multi-threading is the deal with the devil you've made and code that doesn't embrace that reality is just broken.

Agree about the shadowing.

  var x_2 = f(x_1) // never use x_1 again for anything
deserves its own syntax and compiler checks
> Optionally ignoring thread safety seems indefensible

Nobody forces everything to be thread safe. That would either be suicidally complex or suicidally slow. The problem isn't so much "ignoring thread safety", it's that this:

  class Foo(var thing: Int?) {
    fun doSomething() {
      if (thing != null) {
        thing++
      }
    }
  }
doesn't compile and it should. It fails to compile claiming that 'thing' could have changed in the meantime, so it can't safely assume non-null. However, that can only happen if Foo is accessed from multiple threads, but this isn't thread safe nor pretending to be in the first place. You can make the compiler happy by doing this:

  class Foo(var thing: Int?) {
    fun doSomething() {
        val t = thing
        if (t != null) {
            thing = t + 1
        }
    }
  }
But of course that's not remotely thread safe, either. It wasn't thread safe to begin with, and it's still not thread safe now. But this will of course compile just fine. You're forced to jump through hoops to workaround compiler "bugs"

To be fair here the warning isn't actually about thread safety at all, it's to guard against something like this:

  class Foo(var thing: Int?) {
    fun otherThing() {
        thing = null
    }

    fun doSomething() {
        if (thing != null) {
            otherThing()
            thing++
        }
    }
  }
Kotlin has so far just been unwilling to allow the compiler to handle the cases where it could prove that the variable hasn't been modified in the meantime because they can't always prove it.
They can't ever prove it; even just

  class Foo(var thing: Int?) {
    fun doSomething() {
      if (thing != null) {
        thing++
      }
    }
  }
is unsafe as any class user could cons up a Foo t, and call t.doSomething() while racing a modification to t.thing in another thread. There either needs to be a language feature for Foo to live in a restricted threading context or the whole construct is irreparably thread-unsafe. The error is valid because it rejects always-incorrect code.
You're again asserting thread unsafe mutations as a reason. It is not. Or if it is Kotlin is just wrong. Guarding against null in an unsafe thread race is pointless to the extreme. That didn't fix anything. It's pointless to complain about it ever. It's a wrong error in that fixing the error doesn't fix the bug in the code.

There is no possibility of any kind that my snippet is null-unsafe exclusively. My code is null-safe in all situations where the resulting behavior is also correct. And the compiler could trivially prove that.

If they wanted to actually take a stab at compiler-audited thread safety they should add some annotations or such to mark what is guarded by what. Otherwise the only reasonable assumption is to assume thread-compatible. Which my code also runs correctly in.

> Can't cite type inference in Java if one of its most popular platforms doesn't support it. May be ok for you, not ok for everyone though. We might wish Android would keep up, but in the meantime we have practicality concerns.

Google and their J++.

My 5 cents:

It seems to me that the author did not spent enough time to learn Kotlin. The way he mixes Java types (Integer.parseInt) inside pure Kotlin code and then complains about lack of Null-Safety? It is enough to use an extension function String.toInt() to stick to Null-Safety and compiler will do the rest.

His main() function? Another weird argument because Kotlin's documentation has some examples on how to write it. Author lacks understanding of how Kotlin is converted to Bytecode.

Complaining about such insignificant things like class literals or variable name shadowing (there is a compiler warning for that!) makes me want to shout: Hey, Kotlin is the most amazing language ever if those issues ended up as #1 and #4 on authors "bad bad Kotlin" list...

Generally speaking, when someone writes about a programming language in a bit hateful way it is better to learn the language first.

Yup, I wrote a longer form of basically this. I wouldn't want the person posting to make the language decisions at my company.
Or have to work with that person, which is especially bad since one of the goals of this kind of posts is to advertise your company.
A bit too far I'd say. I'd probably happily work with him.
I have seen his other posts and he is a smart guy. No idea what bit him with Kotlin though...
Probably drinking too much koolaid from the AbstractBeanContainerMappingClassFactory... Sadly, this might be a classic example of the the Blurb paradox.
Disclaimer: not super familiar with Kotlin or Java.

Safely calling option.map and having the function assume it's not called with null is very useful. Is that a real drawback to Kotlin or is there something missing from this post?

Calling Optional.map(foo -> foo.bar) is effectively equivalent to foo?.bar in Kotlin. What GP was saying is that the author is using things like parseInt and other non-idiomatic things because the author is not familiar enough with the language. Even if it weren't about parseInt vs toInt, the author could have used "number?.let(Integer::parseInt)" instead of "number?.let { Integer.parseInt(it) }" (but of course "number?.toInt()" is the idiomatic way to convert a nullable string to a nullable int).
Now that I look at the article, it occurred to me that author might have already been biased when trying Kotlin out and was already certain about the outcome hence the rather poor argumentation. The article itself is rather poorly organized and chaotic as well.
There is some value to the criticism where it's easy for Java programmers to do the wrong thing because it's possible when they shift over.

Of course, that's the price you pay for compatibility with Java, but maybe there should be tooling which can give warnings where you are using commonly abused Java tools where you'd be better off using Kotlin-specific ones.

There is, it's called IntelliJ.
I have to agree. Sometimes you do find developers with so much tunnel vision of the "one true way" that it becomes difficult to open their minds to doing things slightly differently.

For example, the null safety example and the complaint that having `!`, `?`, `!!` is "too Scala like" and too complex. I wonder if the author ever had to reason about <? super T> or <? extends T> in Java (e.g. https://briangordon.github.io/2014/09/covariance-and-contrav...). Scala doesn't even have these sigils (there is a different syntax for variance, type bounds and context bounds - but that's about all there is).

Another example - "In the C-family of programming languages, we have the standard way of declaring types of things." At that point you may as well point out that maybe Kotlin isn't in the C family.

First let me tell you that I agree with you, and I just have a small comment.

The type bounds in Java are there for a reason. Kotlin's syntax is simpler but it it unable to express all the types that the Java model can.

I have found myself in situations where I want unable to express the proper type information in Kotlin simply because the designers of the language decided that having full support was too complicated.

Scala does have wildcard types.

List<? super T> is List[_ >: T]

List<? extends T> is List[_ <: T]

Scala leave a feature out? Psht...always room for one more.

Right, you can use _ as the placeholder for a type and it works with the bounds syntax. I probably did not make it clear enough - my point was that Java is also not as "simple" (for some definition of "simple" the author could use) as you'd expect. For good reasons too - these bounds are useful to have sometimes!
"didn't bother" "bitching" "no clue" "another gem" "hateful"

There's really nothing in the article that warrants any of this.

Ok I have overstepped a bit (edited the post), but I will stick to the "did not bother" and "no clue". Documentation for Kotlin is really nice and it is there together with amazing Kotlin Koans online. Do you think that author who so eagerly complains about Kotlin was so eagerly learning it?
It's still pretty much invective (seriously, hateful?) and an invitation to a dumb programming language poop-flinging fest.

As to the author of the thing, they just wrote about not liking Kotlin, you're the one who is taking this as some sort of personal affront. How do you know how long they spent learning it? You don't.

Maybe it is just me but when I critique things then I make sure that I am 100% right. This article, in its current form, can do a lot of harm for people who will read it and decide not to try Kotlin because author has had some problems with Kotlin. Problems that are really easy to get pass by if one reads the documentation and really learns the language with an open mind.
Maybe that's all true but you're not going to fix it by shitcommenting every time you think someone is wrong on the internet.
On the other hand, there's not much of anything in the "article" that warrants much of anything different IMO. It's just not serious.
I learn more about languages from articles like these slagging them --- including languages I end up liking and working in --- than I learn from articles that try to promote languages. I learned more about Kotlin from this than I... wait, no, everything I know about Kotlin I learned from this post.
Some good points, but most of them don't seem like dealbreakers - you could easily get a much longer list of flaws with Java.
interesting function parameter name shadowing issue they highlight. had not run into that, but, wow, that adds some serious confusion.

i also heartily agree with the article's points about nullable types and Java library interop: it's pretty annoying to deal with Kotlin non-nullable types that have to interoperate with existing Java libraries that have nullable types in return values or function callback parameters. i have way more question marks in my Kotlin code than i originally thought i would.

i also appreciated the article's scrutiny of the name and type order reversal in Kotlin and the "::" syntax for getting the class literal (::class vs ::class.java). still trying to get used to that.

and as for the learning curve, i have to admit that it's been steeper than i expected when i first saw introductory presentations. Kotlin feels very abbreviated. the smart type inference and things like 'lateinit' have sometimes surprised me in their behavior. these aspects of Kotlin are indeed very smart, sometimes too smart for me. i feel like i have to think harder to understand a piece of Kotlin code, which is ok, but somehow, i wasn't expecting that based upon the initial presentations.

overall, Kotlin is ok i guess, but, to go off-topic for a sec, as an Android programmer i wondered why Google chose to emphasize adding a new language when many other aspects (e.g. documentation, the jumble of GPS, Firebase, GCM and 3rd party libs, mysterious adb failures, emulator problems, instant run, etc), of the ecosystem needed improvement/simplification/clarification more desperately.

TypeScript also has the weird reversed type declaration. I've never understood it; it's so much less natural to read. Having the type first allows you to easily mentally parse it as "A Foo named bob".
See, that's interesting to me, because I have always read declarations aloud as "bob the Foo", even when they're written "Foo bob". Reasonable people can differ, of course. Where it's harder to differ is that is much easier to parse type-after declarations and to make a consistent syntax with them--that's why Rust et al have gone that route. To do type inference in Java (or C#) they've had to add a new keyword, `var` (and the comedic `final var` in Java), because their declaration structure just wasn't up to doing it any other way.
That makes sense. It's definitely a subjective thing and I used almost nothing but Java and C++ for my first [counts fingers] 6 years of programming, so I'm probably biased.
I'm pretty sure I've used to read them "A Foo named bob".. But I've been in TypeScript and golang land for a while now. I can kinda make sense of it because as an interface the types are what matter most, and the signature in something like F# simply be the input/return types..
for me the trouble begins when i switch between these syntaxes when going back and forth between Java and Kotlin, which i still have to do all the time
It feels weird to me, too, but I'd wager you'd get used to it pretty quick, just as you get used to saying "la pelota roja" instead of "the red ball".

/me hopes he didn't completely butcher the Spanish.

It is not weird, in fact it goes all the way back to Algol, a decade before C was invented.
And the highly popular back in the day Pascal picked it right from Algol... Scala and Go follow the same approach, if I'm not mistaken
And Swift, and Rust, and... Really the C style is the odd one out here.
> Having the type first allows you to easily mentally parse it as "A Foo named bob".

See for me it's more natural to think of it as Eric is a Person, rather than Person named Eric.

There's plenty of decent reasons imo. Its easier to parse and handle type inference (i.e. you don't need to do something silly like have a 'type' that just says "this thing is inferred" ala auto and var). You free up the left side a bit as well which means you can use something like val x = 4 instead of having to write final or const or whatever all over the place. I (and I'm sure most devs) can also just self infer the type of something based on how it's used, so I'd rather have the name of the thing first so I can move on with scanning the code than a probably obvious type.

Also, if your type is something stupidly long (ex. Java) its really easy to read something like MyAbstractFactoryBeanImplBuilder while you have a bunch of stuff in your head and space out/forget something. Humans aren't good at keeping a bunch of things in their heads, so I'd much rather just have the names of these things and then types be as a reference to return to as a "oh wait, what was this thing again?" sort of deal.

And then there are those of us who simply don’t want to see the “Foo” (type) part at all, just Bob (the name).

Others have mentioned the Pascal / Modula / Eiffel type languages, I’m sure, as well as even newer languages that do type inference.

I wanna see the name of the thing on the left margin, rather than AbstractBoilerPlateFactoryFactoryFactory. Or maybe, I don’t even wanna see the thing at all, and just evaluate an expression as a parameter to a function :-)

Java version in the article:

    public int parseAndInc(String number) {
        return Optional.ofNullable(number)
                   .map(Integer::parseInt)
                   .map(it -> it + 1)
                   .orElse(0);
    }
And the Kotlin equivalent...

"No problem one might say, in Kotlin, for mapping you can use the let function:

    fun parseAndInc(number: String?): Int {
        return number.let { Integer.parseInt(it) }
                 .let { it -> it + 1 } ?: 0
    }
Can you? Yes, but it’s not that simple. The above code is wrong and throws NPE from parseInt()."

Yes - that's why Kotlin standard library provides, among many others, a convenient extension function String.toInt(), which is a wrapper around Integer.parseInt().

You're supposed to use that, and then you're safe from NPE, because the receiver has to be explicitly non-nullable (it's String.toInt(), not String?.toInt()).

Also there is no need to redundantly repeat "it" inside the lambda - plus you could further simplify the implementation by using type inference and converting it to expression body:

    fun parseAndInc(number: String?) = number
        ?.toInt()
        ?.let { it + 1 } 
        ?: 0
"Now, compare readability of the Java and Kotlin versions. Which one do you prefer?"

Well, I'll say orElse(0) is more readable than "?: 0" dangling at the end of the expression. However Java is more verbose. I'd say it's a matter of taste.

The difference is that thanks to Kotlin's features - which allow for creating custom DSL easily - implementing orElse is trivial, if you can't live without it:

    fun Int?.orElse(fallback: Int) = this ?: fallback
This allows for:

    fun parseAndInc(number: String?): Int = number
        ?.toInt()
        ?.let { it + 1 }
        .orElse(0)
And this, to me, is already nicer than your Java version.
Or the one I posted below:

    fun parseAndInc(number: String?) = number?.toInt()?.inc() ?: 0
Oh yeah, I forgot about inc().
To me it seems really weird to have the function take a nullable string in the first place (and not obvious that null + 1 == 0), so the right solution is probably to deal with the null values at some earlier stage – but in the interest of further bikeshedding of the implementation, a simple if-expression is pretty clean:

  fun parseAndInc(number: String?) =
      if (number != null) number.toInt() + 1 else 0
Or

    fun parseAndInc(number: String?) = (number ?: "-1").toInt() + 1
;)
So you can emulate map with language features like that. But what about other combinators? filter, flatMap/andThen, etc? Plus of course combinators have the advantage that once you realize that optionals, lists, futures and so on have a common structure, you only need to learn the interface once.
filter, flatMap etc. are provided as extension functions for collections - see http://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collectio...
Yeah, but to me not having Optional with the same interface, and instead language-level syntax for working with nullables, does smell like bad design.
To me java.util.Optional is a crutch; an afterthought. I think it would never come to exist if nullability was done right to begin with. Native approach feels cleaner... to me, of course. For starters - in the context of the quoted code example - what sense does it make to have to allocate a new object (via Optional.ofNullable) every single time parseAndInc calculation is performed?? Wrapper types always involve overhead... perfectly avoidable with a language-level, as opposed to library-level, implementation
Optional/Option/Maybe is the proper way to implement "may not exist". Null is a crutch and language features that try to make it more reasonable to use are crutches on top of crutches. But I agree that in a language that already has null and can't get rid of it, Optional cannot ever be as useful as in a language that was designed properly in the first place.

Wrapper types currently incur overhead in Java. If/when value types are finally implemented, this overhead will become negligible. In languages such as Rust and C++, Optional is already a zero-cost abstraction.

From a type theoretic point of view it's clear that Optional has a monad structure, and all the usual combinators make perfect sense for it and are actually a joy to use in languages that support them, including Java. After all, it's perfectly isomorphic to a list with either 0 or 1 elements.

> fun Int?.orElse(fallback: Int) = this ?: fallback

Or even better:

    fun <T> T?.orElse(fallback: T) = this ?: fallback
An article about Java's warts written with the same pettyness as the author would probably be the length of a small novel.
I would bet that back in 199x there would have been countless articles (more like usenet posts) about "from C++ to Java and back" telling all the downsides and gotchas with Java.
companion objects are one of the best things about modern programming languages. it’s really helpful to think about static and dynamic this way
Could you elaborate please ?

What do they bring on top of static fields and methods ?

they don’t bring any functionality but it is clearer separation. i think it’s easier when you read these components in different scope blocks. they do very logically different things and importing static into instance makes more sense than keeping it all in one. maybe it was just me but i didn’t undserstand static vs dynamic after 4 years of school and into my first job. it took a while to grasp. but now that i know the differences i’d rather keep them isolated
Is it me, or does the article feel like it is written by someone who didn’t actually bother to learn Kotlin. Instead they learnt the bare minimum syntax and tried to write Java in Kotlin.

The author complains a lot about how Kotlin is different from Java. Err.. it is a new language — it is supposed to be different — otherwise why bother?

> I have my favorite set of JVM languages. Java in /main and Groovy in /test are the best-performing duo for me. In summer 2017 my team started a new microservice project, and as usual, we talked about languages and technologies. There are a few Kotlin advocating teams at Allegro, and we wanted to try something new, so we decided to give Kotlin a try.

The opening lines set the tone for the article. The author tried Kotlin because other people wanted to — not because he found it interesting. Most people learn a new language by writing a toy project or two. They don’t start with a real project. And of course it will take time to get used to a new language and be as productive in it as as you were in the old one. The friction is always there, no matter which language you are switching to.

I am sorry, but I can’t take this article seriously — I feel that it’s written for the sole purpose of venting author’s frustrations.

It is just you. Edit: and some hundred others. (using my karma as stats counter)
No thats exactly how it's written. It's written by someone who is so stuck in java land and never bothered learning any other language or paradigms.
I feel the same way: author wants Java and was hoping only for a better Java: compatible with most patterns, tools, even libraries, but addressing some of his pet frustrations. When Kotlin did not satisfy his hopes he got disappointed. Understandably, but I do not see it as the Kotlin problem.

The other problem I have with this post is that it did not state desires/hopes up front. The intro only mentions compile-time null-safety and less boilerplate (for which many languages are better than Java), then adds his desires throughout the text. Thus his complaints seem not a thought through list of failures to satisfy specific desires, but just randomly throwing rocks at vague targets. My 2c.

> a better Java: compatible with most patterns, tools, even libraries, but addressing some of his pet frustrations.

But is this a main pitch of Kotlin?..

Being compatible doesn't mean that compatibility is the path of least friction, especially when it clashes with good design.

A good example of that tension is the final/open thing: Wonky frameworks abuse inheritance and force you to use open all over the place, but Effective Java suggests you should make every class/method final unless you specifically design it to be extended.

> The author complains a lot about how Kotlin is different from Java. Err.. it is a new language — it is supposed to be different — otherwise why bother?

Kotlin advocates try to have it both ways. If it's a full new language, to be evaluated as a full language, then why would you adopt it when it's missing important features compared to Scala? The narrative is that it's a set of small enhancements to Java that are easier to pick up than Scala, but the reality doesn't live up to that.

> then why would you adopt it when it's missing important features compared to Scala

Such as?

There are a lot of things I miss. Case objects, macros, string contexts, (built-in) options as single-element collections, tuples, built-in either, abstract/self types, implicits, etc. We can argue about "importance" or even if those are good things, but we can't pretend that there aren't many missing features. Granted these days I appreciate Kotlin more than Scala, but that is more about tooling and backing.
> We can argue about "importance" or even if those are good things, but we can't pretend that there aren't many missing features.

I don't think anyone would deny that Scala has the most features of anything, it's purely a question of importance. Important missing features is more interesting to discuss than purely missing features.

I've found myself more missing features from C++ when working in kotlin - specifically constexpr & static_assert.

Meh, importance of language features becomes just too subjective. I consider several of the things I mentioned as important, but not important enough for me to choose the language.
At the concrete/immediate level, a nice way to do error handling when you want errors to include a detail message (i.e. a Result/Either-like) - most languages that offer Option-like types let you use a type like that the same way, but in Kotlin the nice ?. syntax only works for "null". Even Java checked exceptions are a better answer for that use case than anything in Kotlin.

Proper immutable types for e.g. collections. If you're writing in a functional style as Kotlin encourages, you want to be able to write functions that accept lists that are required to be immutable, not just lists that the function isn't going to mutate itself. (Scala's collections get a lot wrong but a thing they get right is that e.g. scala.collection.List is a mutable-or-immutable interface that offers only read methods, and then scala.collection.mutable.List and scala.collection.immutable.List are subtypes for mutable and immutable. Kotlin offers the equivalent of scala.collection.List but not the equivalent of scala.collection.immutable.List)

Better support for operations that need to happen in particular contexts - i.e. custom command-like objects. Kotlin has a bunch of syntaxes that could be reused for this - .?, async/await, and plain old collection iteration all need similar syntax, but there's no way to overload a syntax like that for your custom type. (Scala gets this right: for/yield works for options, for async, for plain old collections and more, but also works for user-defined types).

And ultimately, higher-kinded types. (More concretely: the ability to write utility functions like "traverse" that will work the same for various different context-like types).

Re immutable: If you're doing functional why does this matter? "true" immutable vs. just an immutable view should only matter if the object is retained by the function it's passed to, but now we're talking object state rather than pure functions.

Re "command-like" objects: I'm not following, can you give an example of something you can do in Scala here that you can't in Kotlin?

> Re immutable: If you're doing functional why does this matter? "true" immutable vs. just an immutable view should only matter if the object is retained by the function it's passed to, but now we're talking object state rather than pure functions.

For the same reason that being able to write val rather than var matters. With perfect discipline you can write pure functional code in any language, but in practice (and in codebases that likely have some non-functional sections, particularly if you're interoperating with Java) being able to be 100% sure that a given value is really immutable rather than 99.9% sure makes a huge difference.

> Re "command-like" objects: I'm not following, can you give an example of something you can do in Scala here that you can't in Kotlin?

There are lots of different use cases for this stuff, but one I was working with today was database transactions. I have operations that should only happen inside a database transaction, and want to enforce that at the type level, but I want to be able to compose several of those functions in a single database transaction, so I don't want to just have each one run its own transaction. So what I do is have a custom type, something like MustHappenInTransaction[A], which is actually just an alias for an existing library type (Free), and I automatically get the ability to use the for/yield syntax to compose these, and can use existing library functions to operate on it almost as if it were a plain value, but still safely (e.g. traverse rather than map on a sequence). I have no way to "get the A out" except for my doTransaction() function (what's why I say it's a command-like object), so the function will definitely happen in a transaction, but I can still do normal function composition, extract out common subfunctions, and all that.

You can't do that in Kotlin because there's no equivalent to "do notation" or "for comprehension" that you can use for user-defined types, and there are no higher-kinded types so you can't implement generic helper functions like traverse (there's no way to write the type signature it should have).

You can do something like this:

    class MyTransaction {
        fun begin() {}
        fun commit() {}
    }

    fun MyTransaction.query() {}
    fun MyTransaction.update() {}

    inline fun <R> transaction(tblock: MyTransaction.() -> R): R {
        val t = MyTransaction()
        t.begin()
        try {
            return t.tblock()
        } finally {
            t.commit()
        }
    }

    fun test() {
        // update() doesn't compile, no such method
        val hello = transaction {
            query()
            update()
            query()
            "Hello"
        }
        println("$hello") // prints "Hello"
    }
Does that not work for your usage for some reason? Is there a problem with this approach I'm not seeing?
I must admit I don't entirely understand how your approach works, but it seems like it requires all the functions you want to use in transactions to live on MyTransaction (even if only as extension methods)? I want to be able to write normal functions including quite high-level ones that take some business objects and return MustHappenInTransaction[SomeOtherBusinessObject], and pass these return values through generic methods that don't know anything about transactions specifically.

  For the same reason that being able to write val rather than var matters. With perfect discipline you can write pure functional code in any language, but [...]
Strongly agree with you there. This is one of the main gripes I've got with many languages. People just have a "well don't do it" attitude and refuse to see the benefit in the possibility of forbidding mutation. A very important point here is the realization that while the part about discipline might be true, it isn't just your discipline the whole codebase might hinge on, either.

This is the exact reason why making it easy to do the right thing is a very important part of API design; simply by making hacks more laborious than the sane thing to do, you effectively prevent them most of the time.

If you truly need an immutable list there's no shortage of them available. It's more a "is this such a strong, common need that everyone must have it?"

So far I've never needed guaranteed immutability, I've just used kotlin's List (which is an immutable view). If that's the only thing anyone gets then it's functionally guaranteed immutable even though it's not sitting on an immutable implementation.

It's not a case of need versus not; it's that all your lists being mutable creates an extra cognitive drag on everything you do. It's one extra possibility to think about when debugging and trying to understand what's going on when something "impossible" happens (which is what a lot of bugs look like when you're investigating them), right when you can least afford to spare any extra brainpower.

(Kerrigan: Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.)

Sounds like the arrow for kotlin. I think eventually we will see all these things inside kotlin proper but kotlin is pragmatism of idealism not the reverse like scala so in good time for now we have Arrow.
> I think eventually we will see all these things inside kotlin proper but kotlin is pragmatism of idealism not the reverse like scala so in good time for now we have Arrow.

This is an absurd anti-intellectual non-argument. Saying "pragmatism" isn't an argument; if there were actual use cases where the kotlin design was better that would be one thing, but there aren't; it's just inconsistent for no real reason.

There's only immutable List in Scala. Seq or Map would be better examples (they actually come in three versions).
> Kotlin has a bunch of syntaxes that could be reused for this - .?, async/await

Kotlin seems to have reused the hell out of the poor :

> then why would you adopt it when it's missing important features compared to Scala?

What important features are missing?

Why would you use Java when you could use C++ which has a ton of extra features? Or Haskell which has a lot of neat abstractions? Or Python which is super easy to use? Or Lisp which is extremely flexible?

Simple, they all serve a particular purpose. Scala serves a particular purpose, so does Kotlin.

I have found Kotlin to be an easy to use modern language which the JVM ecosystem was IMO lacking. That said, I am not a Kotlin advocate. I’d use if I had to choose from the JVM languages. Otherwise there are plenty of other languages and ecosystems to choose from.

No one likes small enhancements over an existing language in a new language - it is usually not worth switching over. Remember D? IMO, Kotlin developers have made sensible choices in most cases while retaining full Java interop - something I consider an achievement.

> Why would you use Java when you could use C++ which has a ton of extra features? Or Haskell which has a lot of neat abstractions? Or Python which is super easy to use? Or Lisp which is extremely flexible?

Because C++ and Python aren't safe enough, Haskell is too hard to learn, and Lisp is too flexible to maintain. Or maybe you weigh the factors differently and wouldn't use Java, and would pick one of those languages instead.

> Simple, they all serve a particular purpose. Scala serves a particular purpose, so does Kotlin.

I disagree with this as a language design philosophy. Your language may end up being better suited for some purposes than others, but I find languages that aim to be general-purpose tend to work out better than languages that design for a small niche. Scala in particular was explicitly designed to be a "scalable language" that could be used for both large and small programs - and my experience is that it manages that. (Indeed I'd say it doesn't make sense to adopt it as a language if it's not replacing the majority of your stack - there's more to learn in Scala than in most languages, but if you can replace two languages with Scala then that's still less to learn overall).

> No one likes small enhancements over an existing language in a new language - it is usually not worth switching over. Remember D?

Exactly - I think Kotlin has largely made the same mistake as D or CoffeScript, of not being willing to make a big enough break from the existing language in the space. And yet at the same time we see that it's not so easy for a Java user to pick up, either.

> Because C++ and Python aren't safe enough

I wonder what langauages are used in aircraft jets, military, space industry, pace makers ... etc

Often "C" but with enough additional tooling on top to qualify as a distinct language (by which I mean: you can't just pick up a random C library - or a random C programmer - and expect to be able to work with them in that environment). Sometimes Ada. Sometimes others. Sometimes a heterogeneous stack that might include Python in some non-safety-critical parts.
> If it's a full new language, to be evaluated as a full language, then why would you adopt it when it's missing important features compared to Scala?

For all the features it has that Scala doesn't of course, many of which may not be part of the core language (compile times, tooling, backing, simplicity, compile-time null safety, coroutines, quality native compilation, Android support, etc).

The claims about null-safety are pure FUD; once you get past thinking about the literal string enn-you-ell-ell, Kotlin and Scala are exactly as null-safe as each other in all the ways that matter (e.g. as shown in the article, Java interop in Kotlin has exactly the same null-safety issues as in Scala).
Java interop in well-designed Kotlin or Scala is pushed to the edges of the application and fenced off. Kotlin makes null safety a much more practical proposition at that point where Scala doesn't. To be frank, Kotlin's null-handling is one of the bigger reasons I think lesser-skilled developers should use it over Java.

And Scala's is good enough, but it's not as good as Kotlin's. Scala has plenty of other beams in its eye to deal with before getting on anybody else, though (this week's shitfire: developers thinking implicits are a good idea, much as it's been for the last five years...).

> Kotlin makes null safety a much more practical proposition at that point where Scala doesn't.

Nonsense. Putting Option() around any Java-interop calls is no harder than putting explicit "?" types on their return types.

I think it's rather significantly different. The range of inputs to a function in Scala are Some[T], None, and null, whereas in Kotlin they become T and null. Kotlin also uses annotations that exist in libraries--and it understands a lot of them--to turn T! into T or T? directly when it can, which Scala doesn't.

Can you explain how this is so similar to Scala in a way that leaves it up to you to be contemptuous and spit stuff like "nonsense" at people looking to discuss the topic in good faith?

> The range of inputs to a function in Scala are Some[T], None, and null

null is not a legitimate value in Scala. There is no reason to ever use it in a legitimate program; in a situation where you would use null in Kotlin, you use None in Scala. The languages are exactly equivalent (except that Kotlin has confusing inconsistent behaviour when you start nesting possibly-absent types, particularly in the presence of generics), people just get confused because they fixate on the literal source string "null" (and Kotlin marketing encourages this confusion). If you really can't stop yourself from typing n-u-l-l for some reason, use wartremover.

> Kotlin also uses annotations that exist in libraries--and it understands a lot of them--to turn T! into T or T? directly when it can, which Scala doesn't.

Those annotations are often unchecked and therefore unreliable, in the cases where they're even present at all (which are unlikely to be the cases where you need to interop with Java - popular mainstream libraries have them, but those are precisely the libraries for which there tends to be a native Kotlin/Scala replacement available). In any case, the original article is talking about the case where there aren't such annotations.

> Can you explain how this is so similar to Scala in a way that leaves it up to you to be contemptuous and spit stuff like "nonsense" at people looking to discuss the topic in good faith?

Sorry. I've seen enough bad faith from Kotlin people on this topic (and when talking about Scala generally) that I find myself unable to assume good faith.

> then why would you adopt it when it's missing important features compared to Scala?

A useful IDE, much faster compile time, lower cognitive load in daily usage.

"Kotlin advocates try to have it both ways"

Kotlin is a new language. Several of its deficiencies are a result of primarily targeting the JVM. There are no universal Kotlin "advocates" claiming otherwise, and that is fundamental a distracting strawman.

As to Kotlin -vs- "other language", Kotlin has fantastic, broad tooling (being designed by a very competent tooling company gave it quite a speedy start). In an instant it beats out most competitors that force much more of a compromise.

Scala has way to many features to be loved and most people that actually know Scala will tell you most users of Scala are not taking advantage of its features or abusing the ones they know. Go on the other hand a very popular language ( yeah yeah ) probably due to its small feature set
> > I have my favorite set of JVM languages. Java in /main and Groovy in /test are the best-performing duo for me. [...] we decided to give Kotlin a try.

> The opening lines set the tone for the article

He also wrote:

> we decided to stick with Groovy in /test (Spek isn’t as good as Spock).

If they were going to switch from the legacy language for /main code (i.e. from Java to Kotlin), why didn't they also switch from the legacy language for /test code too (i.e. from Apache Groovy to Kotlin) instead of dismissing it with "Spek isn't as good as Spock". And if they use Gradle, why not switch from Groovy to Kotlin for build scripts also.

This was my first take on swift as an Obj-C dev back in 2014. I did an app extension in swift, basically just trying to write Obj-C code in swift (force cast and force unwrap all the things!). I didn't like it, I felt like it got in the way, and probably would've given a list of things like the author that are just lang differences.

Needless to say after my 2nd round with swift it clicked, and then clicked again and again in different ways as the months rolled on. Never looked back.

val list = listOf("Saab", "Volvo")

val map = mapOf("firstName" to "John", "lastName" to "Doe")

The above seems a really strange decision for a "new" language - why would you not just use the most common structure, being JSON?

Perhaps worth noting that none of that is langauge syntax, it's library syntax. mapOf takes vararg pairs: Pair<K, V>, and then the 'to' operator is an infix function that makes a Pair<K,V>.

So you could trivially do your own listOf or mapOf that creates whatever data structure you want, whereas languages with special syntax for this tend to hardcode the result of it. That's a valid choice, sure, but just that there are tradeoffs here rather than it being obviously better one way or the other.

how can a newly designed language not make lists and maps first class citizens?
So that you can use any map or list implementation without them being second-class citizens, that's why.
Because it allowed them to use basic understandable functions rather than writing special use cases. listof and mapOf are just functions and to is just a infix function that makes a pair out of two elements. It makes far more sense for someone making a language.
One of my biggest annoyances in Scala is not having literal syntax for sequences and maps. The language seemingly tries to have every syntax convenience that's ever existed in every language, even when they conflict with each other and cause confusion, and then misses the most basic one.

I've been told that it's because "how would it know which specific sequence and map class you want", but it already has Seq() and Map() which give you the default immutable sequence and map classes, so obviously a literal syntax would give you the same one.

Man i gotta disagree with almost all points in this article.

Name-Shadowing is confusing? Should be common sense to not have multiple variables with the same name in the same scope.

Optionals are ugly in Java-Interop, so we decided to just use Java instead. Great reasoning.

> Name-Shadowing is confusing? Should be common sense to not have multiple variables with the same name in the same scope.

You're saying name-shadowing isn't confusing because it should be common sense not to use it? Then why not just enforce that in the language?

There is an issue in the Kotlin issue tracker to be able to turn warnings into errors, and it was created by a Kotlin team member specifically for this name-shadowing case. So, you will be able to turn any specific warning into an error once this is implemented. Which is nice, I like 0 warnings.
The biggest red flag IMHO with Kotlin is the teams disinterest in supporting the language server protocol. They are taking a very insular approach to the ecosystem just like Microsoft used to with .Net. The world has moved on a bit from that mindset, but they are completely happy with coupling the experience to their companies IDE...
Even if they did support it, you'd be getting a much worse experience with other tools than just using IntelliJ anyways. Given that they've gone through the trouble to write an entire programming language & the amount of value it provides, I really don't mind them trying to use it to push people towards their products a bit. Especially since both IntelliJ Community and the Kotlin plugin are open source.
I agree, all the language server stuff is a win for the scripting and IDE-less ecosystems, but for languages with proper IDE support it is such a monumental step back. So much that nobody working with the existing tooling/IDEs will invest time to implement a language server backend.
I've got a couple languages in mind that have "proper IDE" support, and the vscode experience with them is pretty fantastic as well, even if not perfect.
Could you name one or two? By proper IDE support, I mean support for advanced and precise refactoring, build integration, debugging and so on. Dot autocomplete is only a litte part of it.
"much worse" sounds a bit hyperbolic. Lets assume it would be not as good though, at least at first. It's a little conceited for them to believe they are going to be the best at all things to all people. Letting it out of the nest has greater future potential for wider integration and features in the long run. Maybe Eclipse project or Redhat will eventually do the right by the language..

I don't mind them doing this either. I just find the thinking outmoded, and I also don't mind just not using Kotlin. And to clarify, it's not just the decision to not support language server protocol at this time; it's their reaction to the mere suggestion of it. The language steering is too coupled to the biz IMHO. For what it's worth, I feel the same way about F# and the Visual F# Power Tools team and is the prior experience that raises the red flag.

There isn't disinterest, there are priorities. And this is low on the list for the core team compared to the long list of high priorities. There is the whole playground codebase that anyone (you?) could use to handle the language server protocol.

It is a shame some people are disinterested in helping out. The Kotlin team can only do so much on their own...

"Kotlin changed the extends keyword into the : operator, which is already used to separate variable name from its type. Back to C++ syntax? For me it’s confusing."

Not only C++; C# also. It's not very hard to confuse the author, is it :) I understand it's different from Java he's used to, but that doesn't mean one can hold every such difference against Kotlin. Not being Java isn't in and of itself a fault of a language.

Why is ":" problematic exactly? It's more concise. It's true that this gives ":" more than one meaning, but it's so clearly context-dependent I can't really see how it could cause confusion when coding. An example would help.

(Ruby uses "<" to denote class inheritance - by some miracle Ruby devs manage to get over the fact that "<" is also an arithmetic operator :) )

And that’s not even how C++ uses the colon!
What do you mean? C++ does use a colon for inheritance in exactly the same way as Kotlin.
Ah, I thought the author was comparing cpp to the part “which is already used to separate variable name from its type” which cpp does not do.
>Why is ":" problematic exactly? It's more concise.

Anyone, including non-java programmers, can make an educated guess at what the "extends" keyword does to a java class.

The colon operator is contextless. Unless someone tells you or you've coded in c++/c#, you can't know for sure what it means without googling it.

Here's a case in point, my biggest bugbear with the nim documentation. When you first see nim code, you're gonna see the '@' operator pretty much immediately. You're going to wonder what it does, and google "nim @ operator". You'll then remember that googling symbols doesn't work very well, and google "nim at-symbol operator". Sooner or later, you'll find your way here:

https://nim-lang.org/docs/manual.html#lexical-analysis-opera...

The nim documentation helpfully says "Yes, the @ symbol is an operator".

So what does the @ operator do? It's a mystery, go fuck yourself, errr I mean figure it out for yourself!

If you ignore the mystery and move on with your learning you'll come back to it via the key word "seq" within about 10 minutes, but there's no easy way to search for it if you don't know that, and by the way what a frivolous waste of time.

Shorthand symbols are worth having, but they should be used only in cases where the coding speed benefit outweighs the readability loss. If you had to write "extends" in kotlin instead of use a colon, how often would you be doing it? If it's more infrequent than once every 2 minutes I would argue that "extends" is better because it's in natural language, and thus easier on average for new kotlin developers to understand /regardless of background/.

"If you had to write "extends" in kotlin instead of use a colon, how often would you be doing it?"

Certainly more often than you'll need someone to tell you what ":" in a class declaration does ;)

I see your point, I just don't think this language trait deserves to rank as "confusing" for a professional programmer.

While we're at it, Kotlin, unlike Java, provides explicit "constructor" and "init" keywords. So if it loses points for the lack of "extends", why doesn't Java for not having these?

Nim's manual doesn't seem helpful indeed (they acknowledge it openly in the beginning), but I feel this is sort of beyond the point.

Kotlin's docs are very clear and exhaustive. Case in point - as we discussed inheritance declarations - https://kotlinlang.org/docs/reference/classes.html

>So if it loses points for the lack of "extends", why doesn't Java for not having these?

No one said it didn't :)

In general, I personally prefer my languages explicit for a variety of reasons. There's a balance for sure, and one can go too far the other way. For example, I find Rust to be a shade too unwieldy for my optimum preferences, although I would overlook that to gain the safety benefits if I had the right use case.

> The colon operator is contextless

It has a type after. Always. Even assuming that's not enough for it to click, that Google search took all of 3 seconds and you are now typing ":" over "extends" thousands upon thousands of times. If you honestly thing one of those takes more time than the other, you haven't really thought this through.

This is a silly argument.

>and you are now typing ":" over "extends" thousands upon thousands of times

That's blatant hyperbole, and also a worthless argument. How many times have you typed "int"? Should we replace it with a symbol? Maybe go back to space-cadet keyboards[1]?

J is a language built around symbols for maximum programming speed. It's not an esolang, it's real and usable, and recently updated. Here's a very simple J function:

result=: {&((65 97+/~i.2 13) |.@[} i.256)&.(a.&i.)

Very efficient, minimum keystrokes. Can you tell me what it does?

Fundamentally, programming languages are for people, not computers. Otherwise, we'd all be coding in assembly. Keystrokes are /not/ the expensive or dangerous part of programming, we shouldn't be optimising our languages to reduce them. Optimising languages to reduce miscomprehension is the future, that's where expensive developer time and business risk is concentrated.

Preferring to type a colon instead of the word "extends" is, bluntly, the sort of thing you solve with a custom autohotkeys file.

In any case, it's a minimal gain either way with the : operator, that kind of decision won't make or break any language. But this is the internet and if we're going to argue over something so trivial, I'm going to argue that on the most nitpicky level, "extends" is clearly a better choince than ":".

[1] Space-cadet keyboards are really cool

"result=: {&((65 97+/~i.2 13) |.@[} i.256)&.(a.&i.)

Very efficient, minimum keystrokes. Can you tell me what it does?"

Well; can you tell me what this means? :) https://www.publicdomainpictures.net/pictures/20000/velka/si...

Obviously there are extremes on both sides of this spectrum... It's subjective where the perfect compromise between being explicit and being concise lies. Some languages value the former more (like Pascal or Python...), others are more terse. It's always a trade-off.

"Fundamentally, programming languages are for people, not computers"

Of course, but that doesn't mean the correlation here is as simple as "the more verbose, the better". Otherwise than you imply, verbosity does have its own inherent cost too. It increases the cognitive load on the reader, who now needs to process more text to the same effect, as the meaning-to-text ratio drops.

"Keystrokes are /not/ the expensive or dangerous part of programming, we shouldn't be optimising our languages to reduce them"

It's not about keystrokes though, since code is read much more often than written. Every piece of code written once will be read several times eventually.

So would you prefer eg. begin..end to curly braces? Would you prefer "AND" to "&"? Even wordy language such as Java have been heavily optimized to save space.

It's obviously subjective, but the programming community "votes with their feet", and if you look eg. at the "most loved languages" StackOverflow poll - https://insights.stackoverflow.com/survey/2018/#technology-m... - it doesn't make an impression like wordiness is what people are after in a programming language.

OK, so I’m used to : from doing Pascal back in the 80s, but anyway.

Read the colon as “is a”, and it makes sense.

“counter is a number”

“DogClass is a (special) MammalClass”.

Not seeing a problem there, but again, I have no particular love for curly brace languages. And I would MUCH rather see the type expression spewage AFTER the symbol name - especially given Java 5 generic declarations mixed with Java 8 lambda declarations (yuck!).

Actually, the colon is consistent here: `val x: Integer` means x isA integer; `class Dog(): Animal()` means Dog isA animal. They mean the same thing within their respective contexts.
To add to the authors list:

time kotlinc Hi.kt user 4.5s !! (OK IN IDE on second run)

trailing comma not allowed

no python like package manager. import mail? no

a = b = 1 // assignments are not expressions

Assignment being an expression is a dangerous misfeature in a language with mutable data. It is a good thing to get rid of them, and all reasonable compilers already throw a warning if a program relies on this behavior.
assignment being an expression is not a dangerous misfeature; what the assignment expression evaluates to is important to consider(see ocaml/rust).
No package manager? You can use Maven, Gradle, whatever.
I suspect type declaration order is a deeply personal preference. I hate C-style type-first declarations with a passion; type-last declarations have always felt more readable and natural to me.
I agree (that it's personal) but attributes-first and types-last in the same language is just nuts. That's why the kafkaTemplate function declaration is so ugly.
I read those reasons they switched back to Java, and frankly, I like how things are done in Kotlin better than Java (unless it's identical). I'm not sure what the complaining is about. Looks like the main reason is they don't want to learn a new language.
This is a dumb article
Ok, so, assuming that all the things he mentioned are just nitpicky, what's the upside of Kotlin over Java 10? Lots of people would need adequate training, perhaps some new tools and rewrites. There needs to be a serious upside to get a mainstream company to a niche language.
It's not worth it, Java is getting better and more feature rich that improves programmer productivity. Kotlin is like a cool JavaScript library in the market.
Major thing for Android developers is that the adoption of new Android versions is so slow, we're really stuck with Java 6/7 features. While backend can happily update to Java 15 on their own terms, we're limited by Android OEMs to provide updates to their phones. This is one of the reasons Kotlin is so popular with Android -- you get new Kotlin features when you want to, not when all of your app users buy new hardware (and good luck convincing business people to ditch 10% of the users on old API versions). While we get support for Java 8 (but not 9 or 10) language features via special tool, we still don't have access to Java 8+ APIs.
I could be wrong, but thought a motivation for Kotlin is to get Java-8 and Java-10 power into versions of Android that cant use those levels yet.
It seems like the author likes Java quite a bit. Kotlin, not being Java, seems to be his primary complaint. Take his first point - Kotlin allows variable shadowing. He doesn't say why it's bad or how it caused a bug, he just says that Java doesn't support it and he doesn't like it.

Everyone is entitled to their opponion. But, this article doesn't seem to have much of a point. It would be like if I wrote and article about how I preferred cherry popsicles to grape popsicles. That my opponion and I'm entitled to it. But, I don't know why I'd want to be publish a blog post about it or why anyone else should read it or care.