I've been using Kotlin for about a year now at work. I feel that "IDEA has good Kotlin support" isn't quite the right way to say it. It's become clear to me that the language is explicitly designed to be read and written in IDEA. Receivers (changing `this` per-scope) and `it` (to a lesser degree) are really poor syntax features to read in plaintext. But IDEA automatically adds the plaintext for you so you don't notice.
Genius business move by JetBrains. Get some corporations hooked on some sugar on top of Java, and now they have to pay that fat license forever.
This is a direction jetbrains has been going in for a while. Have a look at the failed https://www.jetbrains.com/mps/
The syntax features I mention only make any sense period within IDEA. But it's just a syntax feature. The value-add is very low! But it's pervasive in Kotlin. That creates the lock-in. In fact, pumping IDEA's seeming value is those features' biggest impact on the average Kotlin developer.
The majority of the valuable code I've written in my life has been Haskell. I do just use emacs, but I heavily use ghci (free and flexible) to aid my understanding.
But most of that Haskell was conceived while I was doing the dishes. So far, my Kotlin has been too tbh.
So IDEA isn't solving the actual critical path of software problem solving. Kotlin and IDEA are sugar for the masses. Nothing more. And I'm pretty sure they know what they're doing when they aren't drunk on their kool-aid.
I think whether you care strongly about syntax is just personal preference. For example, I prefer Elixir to Erlang, TypeScript to JavaScript, and Kotlin to Java even though they could be/are implemented by transforming source code to source code.
On receiver scopes specifically, they make simple DSLs very easy to implement. Arguably needing a DSl is a symptom of design flaws, but Android has a lot of those so receiver scopes makes Android programming a lot nicer.
Edit: I would call this more than syntactic sugar:
interface MyScope {
fun frob()
}
fun foobar(content: MyScope.() -> Unit) {
let scope = MyScopeImpl()
scope.apply(content)
scope.getResultInternal()
}
fun user() {
foobar {
frob()
}
}https://youtrack.jetbrains.com/issue/IDEA-226455#focus=Comme...
It never worked, not even close and I ended up dumping it and returning to VS Code because the remote stuff (particularly to linux VMs and containers) was a deal-breaker.
Real missed opportunity I thought, it had been a long-standing bug when I looked into it, and very very oversold as functionality present in the professional version.