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.