I disagree. Obviously, this is all just subjective preference and opinion, so parent should not take this as me saying they're wrong.
I hate Kotlin's "middle ground" approach.
Scala has persistent data structures for collections, which means that non-destructive updates and copies are cheap. This is great for an immutable-first approach. Kotlin uses Java's mutable collections, so all of the standard APIs in Kotlin make full copies. Sometimes it might even be surprising where copies are made. For example: `listOf(1, 2, 3).toList()` makes a copy of the list instead of just returning it. To understand why this is necessary, see my next point.
Scala's mutable collections are NOT sub-types of its immutable collections. In Kotlin, there is no such thing as an immutable collection interface. You have MutableList and List, but despite the confusing naming, List is NOT immutable because MutableList is a sub-type of List. So any time you write a function that takes a List parameter, you can't assume that it's not actually being mutated from another thread while your function is running. That means that you technically can't even assume a List is non-empty after you check `if (l.isNotEmpty()) { useElement(l[0]) /* this might crash */ }`.
So Kotlin's middle ground approach means that it's inefficient to use the pseudo-functional APIs and its collection types are not concurrency-safe.
Then, there's no error handling mechanism in the language. Well, there's throwing unchecked exceptions. But the Kotlin team tells you not to do that. They tell you not to do that, but that's actually the only thing that is done in the standard library, the kotlinx.libraries, and every single thing that IntelliJ actually publishes. So, it's very "do as I say" with no examples. At least in Scala we have Try, Either, and "for-comprehensions" (a.k.a. monad comprehension, do-notation, etc). Kotlin "recommends" we use sum types to express failures, but without monad comprehensions, it's extremely awkward and verbose, so I've literally never encountered a Kotlin library in the wild that does anything but throw exceptions for business logic failures. I strongly believe that it was precisely to avoid scaring off Java devs that they didn't do do-notation and monadic error handling.
I don't mind colored functions. I do absolutely HATE that Kotlin coroutines use exceptions for control flow and business logic. It's so hard to correctly handle sub-jobs in coroutines in any non-trivial case with cancellations, etc.
They also decided to not do type-classes, so we get half-baked, ad-hoc, cherry-picked type-class-like features such as extension functions and multi-receivers. I especially dislike extension functions because the receiver is resolved statically (it has to because of how it works under the hood), which is NOT the way regular method calls work, which adds yet another inconsistency to the language that's impossible to catch at compile time.
Ugh. And I'm working on Kotlin code today, so now I've got myself all upset about it. lol.