<@U5QGY080J> <https://kotlinlang.slack.com/archiv...
# language-evolution
i
Thanks for looking that up!
And ok... Though I'm not sure why exactly it is bad to use currying in combination with OO receivers 🤔
k
No prob! And no idea; it's not my interest-field. Maybe @dmitry.petrov can help you?
d
Not really bad, it just rarely feels "natural". See, many FP APIs are designed with currying-based pipelines in mind; many OO APIs are designed with receiver-based pipelines in mind. Mix those two, and you get some weird punctuation soup ;) (if you do a lot of Scala, you should be well accustomed with punctuation soup, though). From the language design perspective, OO doesn't play very well with currying, mostly because the receiver type affects the scope where the callee is resolved. So, it's kinda hard to define practically useful "curry-by-receiver" operator in ML-based languages such as F#.
Regarding libraries design. In functional languages you often design APIs so that it's easy to chain calls based on currying. Obligatory ML/F# example:
Copy code
xs |> List.filter foo |> List.map bar
Here
filter
and
map
take list as a last argument, so it's easy and natural to build pipelines using
|>
operator (which is defined simply as
let (|>) x f = f x
). In Kotlin,
filter
and
map
are extension functions on receiver of type
List<T>
, so it's easy and natural to build pipelines using call chains:
Copy code
xs.filter(::foo).map(::bar)
It's not quite practical to use currying-based pipelines when all your standard library is designed with extension functions and call chains in mind, and vice versa. In languages like Scala there's a considerable deal of special syntax to build functions out of functions (here by "special syntax" I mean stuff like
_
arguments; of cause, it also has a lot of function composition operators in libraries).