If you’ll forgive me venting a little bit it’s just really frustrating that the community seems to have given so little thought to the downstream effects of removing currying from the language.
I read the entire thread discussing the justifications for the change and the great majority of the reasons seemed to involve external bindings. Well, personally for my team it’s extremely rare that we run into any problems with correct bindings because of currying and they are easily addressed when encountered. But challenges with external bindings could be solved simply by extending or modifying the binding system and syntax as needed, which seemed to hardly be discussed as a consensus on changing to uncurried-by-default was reached (or perhaps, was declared. I saw plenty of people objecting to it in that thread but they seem to have been ignored).
Another concern was the difficulty of understanding currying. In my opinion this is both overstated and unimportant. All languages have a learning curve of some kind and as far as languages go I think rescript is quite approachable. I don’t think currying significantly complicates it, and though I had a haskell background before rescript, no one on my team has had trouble understanding currying even if they don’t come from an FP background.
Some other concerns were about overhead of Curry.X calls, or the need to put a () as the last parameter when using optional named parameters. But no one provided any numbers to justify that the overhead of currying created any performance hit, and others in the thread suggested that according to their testing it didn’t. The need for a terminal () is completely inconsequential in my opinion. It’s just something you do it and everything works just fine.
Then there’s the fact itself that we’re losing the currying feature and the expressiveness that comes with it. Almost uniformly, updating our code to be uncurried-compatible has resulted in less readable, more verbose, and/or redundant code. It’s extremely frustrating to not only have to spend hours updating function calls throughout or codebase, but to be replacing neat and expressive code with a garbled mess of nested function calls and single-argument lambdas in the process. I used to be able to write json |> field("myField", array(string)), now I have to write field("myField", array(string))(json). I used to be able to write Js.Array.map(config->getValue), now I have to write arr => arr->Js.Array2.map(v => config->getValue(v)). Is it minor? Perhaps. But it’s uglier, and it was forced on me.
Based on justifications which I really don’t find convincing, the rescript team decided to make a massive change to the language semantics which broke dozens of packages and thousands of modules. Our company has over 200k lines of rescript code, we’re heavily invested in the language, and this change has made the effort required to upgrade to the latest version, rewriting thousands of lines not just in our app but in many dependencies, all to solve a so-called problem that for us never was a problem, on the contrary it was a valuable feature.
I realize the train has left the station at this point but after all the time I’ve spent on this upgrade, and with an unknown amount of work left to go, I have to say something.