Kotlin doesn't really support FP in the modern sense of the term; effects are all special cases in the language (null, async), so you can't abstract over them generically (e.g. you could never implement "traverse" in Kotlin because you can't even write the type signature it's supposed to have) and you can't use a custom effect if you want to do something the language designers haven't thought of. E.g. there's no nice way to do validation where you want to have a message in the case of failure (in some ways this is actually a regression from Java, which at least had checked exceptions for this kind of use case, not that they're a great solution).
The thing that Scala has and Kotlin completely lacks is the tooling to allow you to avoid runtime reflection. Typeclasses and macros (and especially both together) are way too powerful-yet-principled to give up once you're used to them.
Annotation processing is impossible to reason about; it's equivalent to macros but much less visible.
Most Scala doesn't need macros (other than those inside shapeless) because Scala has a) higher-kinded-types, for/yield and an existing library for working with context-like types, and b) generic traversal of object graphs via shapeless. Between them those cover virtually all the use cases for annotation processing, macros or anything like that.
I agree that most application-level code doesn't need new macros (you rarely have to develop a new macro to add a feature to an application) but there are definitely a lot of very legitimate use-cases for them outside of Shapeless. To give just a few:
Even for cases where inductive implicits can do the job, there is still a bit of a push to prototype with shapeless and then rewrite with direct derivations of your instances later on to improve compile times. See e.g. https://github.com/circe/circe-derivation.
macwire and scala-async are bad ideas in my book (having worked on codebases that use them) and I suspect the same of machinist and refined; they're both making too big a change to the language to make sense as a library, the cost/benefit doesn't stack up. (I do think prototyping language improvements is one other thing macros are good for, but that's not something you'd do in production code). quicklens looks like a reimplementation of the same stuff that shapeless does, so not really a different use case.
There are performance problems with inductive implicits in the current compiler; I'd rather see that fixed at the compiler level (I believe there's already a PR?) than see every library try to work around it. Actually I'd like to just build something like Shapeless' functionality into the language proper; I'd say e.g. case classes and sealed traits should have come with the equivalent of LabelledGeneric already.
macwire and scala-async are bad ideas in my book (having worked on codebases that use them) and I suspect the same of machinist and refined
We'll just have to disagree on these sorts of "power tools", I think.
Quicklens does a lot more for you than Shapeless's lenses, which to my knowledge not very many people are using for new projects at this point. I think once the Cats port lands, I'll be moving to Monocle for my own stuff, though (I think this will be the trend).
Of course, the compiler getting better about inductive implicts can only be a good thing, but I do think there may be some upper limit to what can be done short of an effort similar to what Eugene is taking on with Reasonable Scala, since they are using a typechecker as an unwitting computer when we program that way. The work that Miles did to improve inductive implicit performance is tremendously helpful but it does not fully solve the problem. As an example, my very-induction-heavy codebase compiles about twice as fast with his patch enabled. That's nothing to scoff at and is super-impressive for a single patch, but it doesn't make the problem evaporate.
I fully agree with you that it would be great if Generic-like stuff were baked into the language. To me, that sort of thing is the only compelling use-case for whitebox def macros. I feel like things would be better if we could just drop those.
I find continuation-based stuff impossible to reason about; the only way I can understand the flow is in terms of values i.e. futures. And if we're working with futures I'd rather have them work as a plain old monad with for/yield that looks like any other monad, rather than having to remember what some unique future-specific syntax desugars into.
> Annotation processing is impossible to reason about
Maybe for you but given how popular annotation processing is on the JVM (and especially on Android), plenty of people are reasoning with them just fine.
Actually, it's so popular and easy to use that it's slowly replacing reflection in pretty much every library I've seen.
"Better than reflection" is a low bar, and I'd suspect it's more popular on Android precisely because better alternatives like Scala are less popular there (and also because Android codebases are smaller, so can get away with more unreasonableness).
In my experience, annotation processors are definitely way harder to reason about than def macros in Scala (especially blackbox ones). I find them to be about as hard to reason about as macro annotations despite being less powerful. They are also way harder to write and distribute and not at all an analogue to typeclasses.
Kotlin looks very nice. But I think there are languages with better concurrency support - Elixir (cheap green threads in the VM) and Scala (actors and futures) come to mind.
I think it really depends on your use case too. Kotlin is great for mobile apps and games, where coroutines are fantastic (see also C#/Unity there). For writing scalable web services, you need more control and resilience. There Elixir and Scala are the heavyweights.
1. OOP: https://www.packtpub.com/mapt/book/application_development/9...
2. FP: https://blog.plan99.net/kotlin-fp-3bf63a17d64a
3. Concurrency: https://kotlinlang.org/docs/reference/coroutines.html
4. Native: https://github.com/JetBrains/kotlin-native
5. Simple: https://try.kotlinlang.org/