
From Java to Kotlin and Back Again - krzyk
https://allegro.tech/2018/05/From-Java-to-Kotlin-and-Back-Again.html
======
__sr__
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.

~~~
lmm
> 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.

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

Such as?

~~~
lmm
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).

~~~
kllrnohj
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?

~~~
lmm
> 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).

~~~
kllrnohj
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?

~~~
lmm
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.

~~~
kllrnohj

        typealias MustBeInTransaction = MyTransaction.() -> Unit
        
        fun makeObject(i: Int): MustBeInTransaction {
            return { /* do something with i or whatever in a transaction */ }
        }
        
        fun test() {
            var genericArray = arrayOf(1, 2, 3).map { makeObject(it) }
            //genericArray.forEach { it() } // fails to compile
            transaction {
                genericArray.forEach { it() }
            }
        }
    

Like that?

~~~
eeperson
It is interesting to see that is possible in Kotlin. I just learned a lot
about receivers (as an aside, do you know where I can find better
documentation? The best I could find was a stack overflow post).

I think this issue with this is what happens when you combine DB transactions
with async queries with errors and null handling? It seems like you have to
combine 4 different mechanisms in order to do this (receivers, async/await,
try/catch, if(null)). Is there some way to do this all with receivers? It
seems like they don't really compose.

The 'command' version in Scala could be written roughly the same way for any
combination of the 4 features (the types would just change). For example you
could write a Scala version of your original example as:

    
    
        def test(): Unit = {
            // update() compiles but doesn't do anything to the DB
            val helloDBOperation = for {
                _ <- query()
                _ <- update()
                _ <- query2()
            } yield "Hello"
            
            val hello = db.run(helloDBOperation)
            println("$hello") // prints "Hello"
        }
    

This would look almost exactly the same no matter which combination of the 4
features you use.

EDIT - it looks like I somehow also accidentally replied to you with an
earlier version of this comment. Unfortunately , I didn't notice until it was
too old to delete or edit. Please ignore the other comment that is very
similar to this one. Sorry about the confusion.

~~~
kllrnohj
> as an aside, do you know where I can find better documentation? The best I
> could find was a stack overflow post

[https://kotlinlang.org/docs/reference/type-safe-
builders.htm...](https://kotlinlang.org/docs/reference/type-safe-
builders.html)

It's more designed to build DSLs or similar, so you'll find more
documentaion/examples in that area of the docs.

> I think this issue with this is what happens when you combine DB
> transactions with async queries with errors and null handling? It seems like
> you have to combine 4 different mechanisms in order to do this (receivers,
> async/await, try/catch, if(null)). Is there some way to do this all with
> receivers? It seems like they don't really compose.

It's just a closure with a compiler-added paremeter. It can be nullable if you
want and exceptions work the same as any other closure. If you want
async/await you'd use coroutines. I think coroutines and receivers mix just
fine, you'd just make the type a suspending lambda with receiver, but I've
never tried.

~~~
eeperson
> [https://kotlinlang.org/docs/reference/type-safe-
> builders.htm...](https://kotlinlang.org/docs/reference/type-safe-
> builders.htm..). > > It's more designed to build DSLs or similar, so you'll
> find more documentaion/examples in that area of the docs.

Thanks for the link. However, I feel like that still doesn't give a lot of
detail. Can you have multiple receivers? Can receivers be generic? Can
receiver resolution be controlled by other arguments?

> It's just a closure with a compiler-added paremeter. It can be nullable if
> you want and exceptions work the same as any other closure. If you want
> async/await you'd use coroutines. I think coroutines and receivers mix just
> fine, you'd just make the type a suspending lambda with receiver, but I've
> never tried

Sorry I didn't mean to imply that Kotlin was incapable expressing all of these
things together. I meant it would be desirable to express all of these things
with the same tools. It seems like the you would have to express these with
several different paradigms and be aware of how they interact. That also means
you would need more boilerplate because you have to abstract each of these
things separately.

------
johnwick17
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.

~~~
solidninja
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...](https://briangordon.github.io/2014/09/covariance-and-
contravariance.html)). 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.

~~~
paulddraper
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.

~~~
solidninja
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!

------
V-2
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.

~~~
ptx
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

~~~
V-2
Or

    
    
        fun parseAndInc(number: String?) = (number ?: "-1").toInt() + 1
    

;)

------
forfengeligfaen
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)

~~~
kjeetgill
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?

~~~
cmurdock
I think the big use-case is on Android where you're stuck with Java 7 and
therefore can't use lambdas.

~~~
dlubarov
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.

~~~
cmurdock
Ah interesting. Thanks for the info.

------
V-2
_" 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 :) )

~~~
Sir_Substance
>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...](https://nim-
lang.org/docs/manual.html#lexical-analysis-operators)

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/.

~~~
V-2
_" 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](https://kotlinlang.org/docs/reference/classes.html)

~~~
Sir_Substance
>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.

------
bberrry
An article about Java's warts written with the same pettyness as the author
would probably be the length of a small novel.

~~~
marcodave
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.

------
cesarb
The author wrote a lot about nullable types, but didn't mention a very useful
feature of the Kotlin compiler: it understands several (IIRC, more than a
dozen) third-party Java nullability annotations. It treats Java types
annotated with @NotNull or equivalent as T, types annotated with @Nullable as
T?, and only types with neither are treated as T!.

And on the other direction, the bytecode generated by the Kotlin compiler also
has these Java nullability annotations (it uses the org.jetbrains annotations
package), so for instance Dagger2 can know that a type is nullable from the
presence of the @Nullable annotation.

If your code already uses @NotNull/@Nullable everywhere, introducing Kotlin to
your code base becomes easier. As a bonus, IDEs can sometimes use these to
warn you of potential null pointer mistakes in your code.

------
Rapzid
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...

~~~
jrs95
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.

~~~
ysleepy
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.

~~~
Rapzid
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.

~~~
ysleepy
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.

------
dagenix
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.

------
anad7
I've said it earlier, I am saying it again. "Kotlin enthusiasts or rather PR
representatives cannot stomach criticism", this is quite visible on the blog
itself and here on HNews.

Consult with your CEO, CTO and/or Director of Engineering before switching to
Kotlin, there may be things you might not be aware of, think 20 years ahead
and think objectively about the pros/cons before heeding to advice of the
enthusiasts, they won't be there to help you when your app behaves
unexpectedly, or if your tech debt increases or when you are unable to find
people willing to work with your messed up code base, remember there's no
reverse Kotlin to Java converter built into IntelliJ.

My advice is to sit it out and wait for Java to evolve, which shouldn't be far
away, in the meanwhile enjoy writing your code in Java in which you have your
actual work experience(8+ years in my case), which has books and resources
dedicated to help you understand the pitfalls, design patterns and every trick
out there since 22+ years of its existence. Besides I would recommend
developers to not waste their time on a language which piggy backs on JVM,
many other languages which did that or are doing it have failed, Kotlin won't
be an exception. Instead use Java to learn and write complicated Data
Structures and Algorithms and learn technologies like Machine Learning, Neural
Networks and AI etc to increase your job prospects.

~~~
apatrida
I'm a Kotlin enthusiast (since 2013) who has also used Java since 1995 and was
quite the enthusiast for many of those years, tracking the progress of Java in
detail since inception. I've contributed to both languages. Just so you are
aware of my background being strong in both.

Now back to this blog post and enthusiastic defence of Kotlin:

This blog post wasn't a criticism, it was instead under-informed and
misleading. You will indeed attract the attention of enthusiasts if you take
an authoratative viewpoint against the thing those enthusiasts care about,
publish it publically, promote it to the whole community, and use bad (or no)
evidence in the process. Who wouldn't stand up and protect something they care
about in that circumstance?

By the way, when we were helping to create Java at Borland, we were told many
things like you just said: "it will fail", "the CEO/CTO/CIO won't want it",
"we can't take the risk", "in 20 years it will be gone", "it's just a toy and
not for the enterprise", "dancing Duke is all it can do", "it will fail like
the others, Java is no exception", "no real application will be written in
it", "it can't do server-side", "stick with C++", "stick with Delphi", "stick
with VBA", "stick with PHP"

So obviously the prognosticators and non-enthusiasts were wrong. What makes
you better are reading the future than they were? Is Google wrong when backing
Kotlin? Is JetBrains? Is Square? Is the Spring Team? Is the Gradle team? Is
the JUNIT team? Or are these some of the same people who made the right call
on Java way back in 1995-2000 as well? In fact Java would have failed had the
enthusiasts not carried it through tough times, shaped it up, improved
performance, fixed critical bugs, cleaned up bad specifications, and showcased
it to the world. Because of enthusiasts, you have Java.

So let the enthusiasts do their work of defending a good thing against people
that just don't yet see the light (or maybe never will care to, so bet it).

------
eropple
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 I'm at it, I'll give my one real grinds-my-gears thing
with Kotlin: 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 get the resemblance to Ruby but I think their choice of `->` makes it read
oddly. But that's a minor nit compared to the real one: `it` is a wart. I
think you should have to name your enclosed variables and I don't think you
should be able to shadow them. Heck, the reason I read this article in its
entirety in the first place is because the author's first point about name
shadowing is a good one...

~~~
on_and_off
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.

~~~
eropple
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.

~~~
on_and_off
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.

------
tabs_masterrace
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.

~~~
choward
> 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?

~~~
apatrida
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.

------
ender7
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.

~~~
bcoates
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.

------
lokedhs
When I saw the first compliant he had, about variable shadowing, I was asking
myself: This guy works for Allegro and he doesn't understand shadowing? It's
used all the time in Lisp.

Then I realised it's a different Allegro.

Another case where knowing Lisp makes you a better programmer, no matter the
language you use.

------
V-2
The particularly funny thing is how the blog admin - the author himself? -
censors comments not to their liking, marking them as spam : ) They clearly
are a bit touchy.

Below, the comment he's deleted twice; you be the judge :) (I wouldn't
normally repost, but the first time round I erroneously assumed it was due to
including a link in it; apparently not).

\----

 _The article has been commented extensively on Hacker News. I 'm not pasting
the link, as this gets my comment marked as "spam" (go figure), but it's
trivial to find it with very basic google-fu.

Now, while I don't approve of the unneccessarily biting tone of some of the
remarks posted there, I think it's been demonstrated convincingly that a large
share of this Kotlin critique is highly dubious at least.

I believe that in general the longer we work, the less eager we are to learn
new stuff, and we become more set in our old ways. It's only natural and
human, but often we go to great trouble only to rationalize this attitude
somehow. And that's what should set your alarm bells ringing. For the sake of
your own development, nobody else's.

Publicly criticizing a language without even knowing its standard library (as
evidenced by the "Integer.tryParse" example, which indeed runs into troubles,
but only because it's outright wrong - see the comments on Hacker News for
more details) seems premature, especially for a veteran programmer like the
author._

\----

To me there are two takeways here; more important than Kotlin. Two factors
that inhibit our professional development, especially in the long run, once
we're "seniors" already.

The first is what I already pointed out in the blacklisted comment, above.

The other is sort of self-evident now; and that's the ego problem. Not only we
become conservative over time; we also develop an oversensitive ego, and
conversely, an allergy to being corrected. I really hope I won't fall into
this trap myself... I sure as hell exhibit similar signs now and then

~~~
apatrida
That forum (disqus) is very very bad at spam detection. And hates links in
posts.

------
peter303
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.

------
V-2
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...](https://github.com/gojuno/koptional/blob/master/koptional/src/main/kotlin/com/gojuno/koptional/Optional.kt)

 _" 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"...

~~~
kllrnohj
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()

------
xchaotic
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.

~~~
wasyl
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.

------
hoodoof
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?

~~~
kllrnohj
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.

~~~
singularity2001
how can a newly designed language not make lists and maps first class
citizens?

~~~
kllrnohj
So that you can use any map or list implementation without them being second-
class citizens, that's why.

------
HillaryBriss
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.

------
kodablah
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 share the ones in the article.

~~~
bcoates
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

~~~
kllrnohj
> 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.

~~~
bcoates
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.

~~~
kllrnohj
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.

------
IshKebab
Some good points, but most of them don't seem like dealbreakers - you could
easily get a much longer list of flaws with Java.

------
s73v3r_
The crux of this is that they're not doing Android stuff, so they have the
luxury of using Java 10.

~~~
stevenwoo
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.

~~~
forfengeligfaen
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.

------
alexeiz
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.

------
_bxg1
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".

~~~
eropple
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.

~~~
_bxg1
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.

------
kevinr
This is a really useful article. What I really want is Java-minus-Oracle, and
it sounded from some of the chatter around Kotlin like it might be that, but
it seems what I really want is Groovy.

------
foolfoolz
companion objects are one of the best things about modern programming
languages. it’s really helpful to think about static and dynamic this way

~~~
on_and_off
Could you elaborate please ?

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

~~~
foolfoolz
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

------
madmulita
Can't comment on the java vs kotlin thing, but what 'microservice' takes
months to write by a team?

------
jillesvangurp
I've been spending some quality time with Kotlin the past few weeks and have
been converting some of our Java code. The fact that this is easy and that you
can mix java and kotlin code makes the transition very easy. Mostly the
transition has been pretty smooth and I'm liking this enough that I don't
really care about switching back to Java at this point. For reference, I've
been doing Java since 1996. It's been my primary language for most of that
period. Kotlin is a big deal for me and I'm not doing this on a whim. I've
been following Kotlin progress for years before deciding to switch.

What this author seems to get hung up on is that not all Java idioms port well
to Kotlin. Some of his criticism is fair, e.g. the companion object thing is
indeed a bit of a kludge. No matter how the Kotlin people spin it, the fact is
that it is coming up frequently in forums, stackoverflow, etc. It's clearly a
problem and it is entirely fixable.

So, it would be helpful if they added proper support for static fields and
methods without requiring ugly annotations and offer full back and forward
compatibility to Java. The JVM supports it and clearly their compiler supports
it if you get insistent with the right amount of ugly annotations and
verbosity. So, I see no sound technical reason for not doing this. However, it
is not a show stopper. Companion object with some functions, add @JvmStatic
annotations, problem solved.

There definitely are some more ugly corners in the language but mostly is
clearly better than Java. And just because it's there doesn't have to mean you
have to use all of it all the time. Adding question marks all over the place
doesn't look like idiomatic Kotlin to me. Better to just have null safe code
and not having to deal with nulls. Also, java.lang.Optional works just fine in
Kotlin and kotlin probably adds some useful extension methods.

Otherwise, sane generics, extension functions, flexible property definition,
data classes, no difference between boxed/unboxed primitive types, etc. All
great stuff and kind of refreshing after dealing with Java's broken type
system for years.

Add to that the upcoming support for co-routines, javascript (you can do react
apps in kotlin) and native compilation, and the endorsement for android
development, awesome tool support, etc. and you have a great language that is
ready for just about anything.

So, mostly good stuff to say about Kotlin. As for Scala/Groovy, I never really
cared for either. I'd say Kotlin's strength is that it cherry picks a few
popular things from those and other languages without really trying to be
those languages. It's seems to be succeeding where those languages failed in
trying to get Java developers to abandon Java. Java 10 is a nice incremental
change but doesn't really address most of the things that Kotlin fixes.

------
iddan
This is a dumb article

------
apatrida
A comment I posted on that blog post, that likes to keep going to spam box.

1\. _Name shadowing_ is a compiler warning. It is good to pay attention and
clear all warnings by resolving the issues. It isn't a secret when you name
shadow, and a developer I would hope would pay enough attention to not do it
on accident. I've used Kotlin since 2013 and don't think I've shadowed a name
even one time on accident. There is an issue in the Kotlin tracker to allow
turning specific warnings into errors, this would give you the behaviour you
want once added.

2\. _Kotlin type inference is the best_ out there, nothing compares in
accuracy and scope. You aren't getting the same thing from Java 10 that Kotlin
has by far.

3\. _Compile time null safety is accurate_ from Java libraries if they inform
as to their null safety, for example there are many libraries that use
`@NotNull ` and `@Nullable ` annotations and Kotlin respects and enforces
those. They also handle this for JDK calls so that all standard library calls
are correctly interpreted. You can fix your own custom Java libraries which
also helps with Java static analysis. And eventually you'll use more and more
calls to your own Kotlin code or to Kotlin libraries and you'll really be glad
all of this null safety is there and part of the compiler.

4\. _Class literals are many times not used in Kotlin API design_. Instead you
as an API designer would just write an extension function that reifies the
generic parameter and auto infers the class literal. Or you can do it yourself
to extend any API you wish. You will only do that once and then enjoy the
magic a thousand times after. There are actually modules for things like
Jackson and GSON that do this already. So then the syntax is better than the
Java because you don't have that parameter at all (which is type erased
whereas reifying the full generic type is not). Here is an example of Java vs.
Kotlin using Jackson object mapper in the same use case you were
demonstrating:

Java:

    
    
      final MyStateObject state = mapper.readValue(json, MyStateObject.class)  // type erased, which sometimes is ok
      final List<MyStateObject> states =  mapper.readValue(json, new TypeReference<List<MyStateObject>>()); // not type erased
     
    

Kotlin:

    
    
      val state: MyStateObject        = mapper.readValue(json) // not type erased
      val states: List<MyStateObject> = mapper.readValue(json) // not type erased
     
    

Alternative Kotlin:

    
    
      val state  = mapper.readValue<MyStateObject>(json)       // not type erased
      val states = mapper.readValue<List<MyStateObject>>(json) // not type erased
     
    

Isn't type inference wonderful? Especially with reified types making API's
like this possible.

5\. _Type declarations_ in the form of `name: Type ` are by design to allow
for unambiguous syntax which keeps the language smaller and leaner than the C
style typing which cannot be used everywhere without extra cruft to delimit
what is going on. Plus this is more readable when scanning variable
declarations since they are at a fixed position from the left instead of a
random position on the right. Here are some good reading for you that let you
know the Java style `Type varName ` is actually the less common across
languages:
[https://softwareengineering.stackexchange.com/a/311739/20888...](https://softwareengineering.stackexchange.com/a/311739/208884)
and then this post about how it interferes with higher level concepts in
language to have it backwards as Java does:
[https://softwareengineering.stackexchange.com/a/311730/20888...](https://softwareengineering.stackexchange.com/a/311730/208884)

6\. _Companion objects_ are there so they can be extended, including with
extension functions. You can easily do things like logging using other models
and delegates instead of adding a companion object. Your logger system likely
caches the logger by the way so having a reference on the object is not a huge
item to add. You can also have a `main()` as a top level function and is not
required to be in a class which probably makes more sense for a main anyway.

7\. _Collection literals_ are not present in Kotlin because in the JVM
developers are more specific about the exact type of collection they wish to
construct, and there are simple helper functions which make things clearer.
The `: ` being used for maps would overuse that symbol and cause it to have
different meanings (I think you complained about two uses of `: ` then you
later suggest a third). What is wrong with `to ` for creating a pair which is
used to create the map? it is an extension function, highly readable, and you
can actually make your own with some other name (other than `: `) `to ` isn't
part of the language syntax nor forced upon you. The Groovy syntax is bad
because it looks like you are declaring a list/array. The other syntaxes don't
say whether the maps are readonly or mutable and that is important in Kotlin.
It is a carefully thought through issue.

8\. _Maybe?_ is not needed as much due to alternatives and null safety. But,
there is the JDK _Optional_ which you are showing and can just as easily be
used by Kotlin as well. And more "native" versions in open-source Kotlin
libraries. Kotlin just doesn't have one in its standard library, nor does it
need one. I personally dislike API designs that force optionals on me for
everything, so I'm glad Kotlin doesn't.

For your example code, why are you using Optional for this case of
`parseAndInc `? Kotlin has the `?. ` safe operator to continue a chain when
not null, and the `?: ` Elvis operator to provide a fallback on null values.
Any operator like `+ ` is also available from its operator function (i.e.
`plus() `) or in this case simply `inc() `. Therefore:

Kotlin:

    
    
      fun parseAndInc(possibleNumber: String?) = possibleNumber?.toIntOrNull()?.inc() ?: 0
     
    

Yet you can also write the same Kotlin code as your Java example (and slightly
less typing):

Also Kotlin:

    
    
      fun parseAndInc(number: String): Int {
        return Optional.ofNullable(number)
            .map(Integer::parseInt)
            .map { it + 1 }
            .orElse(0)
      }
     
    

Compared to your Java:

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

Please remember that everything you can do in Java you can do in Kotlin
including using all those Java classes you are familiar with. But, you can
also learn idiomatic Kotlin and write it differently. This is one of the
reasons the learning curve is very low.

9\. _Data classes_ , so you aren't complaining here or are you? You can't
inherit the equivalent in Java either, you would have to rewrite `equals `,
`hashCode `, `toString ` and more if you did that and each would need to be
customized. So Kotlin has the same issue, inheritance of these is dangerous
because manual decisions need to be made in order to do so. You CAN inherit
from another class, and you could use composition and interfaces instead. Data
classes are a life saver in code, covering a huge number of cases without all
the boilerplate of manually coded JavaBeans.

10\. _Final classes by default_ are a good thing, and this has been heavily
researched and talked about in the Java community as a best practice. Some old
Java libraries do not know how to handle this because they don't expect it to
be a problem. But those libraries are changing, and complier plugins for these
libraries already help you out with 0 effort in changing code. Plus, newer
libraries deal with this without problems. If you want to modernize, you have
to modernize and not just expect new things to continue with allowing bad
habits because some legacy code doesn't do things elegantly. I can't think of
any blocking case related to this. It was well known, well covered, and is a
non-issue.

11\. _Shallow learning curve._ Kotlin is small language, consistent, and
elegant. It does NOT have a steep learning curve. It is no where near Scala in
terms of effort and complexity, yet you lump it in there anyway. Plus, isn't
it worth learning a language over a week that'll save you 40-50% the lines of
code, automatically eliminate whole categories of bugs you write, be many
times more readable and maintainable? Kotlin is a few days to a week for an ex
Java developer to write reasonable code, and then later they'll write more
elegant code over time.

And about _Spock vs. Spek_ : You don't have to pick either/or, since you can
use Spock from Kotin too like any other Java library.

------
singularity2001
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

~~~
tathougies
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.

~~~
xfer
assignment being an expression is not a dangerous misfeature; what the
assignment expression evaluates to is important to consider(see ocaml/rust).

------
bitL
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") ;-)

~~~
V-2
Heinz is American (and, in the context of the article, a global brand), not
Russian.

~~~
bitL
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.

~~~
V-2
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

