"Open letter" on why I won't be advocating for rescript anymore

Hiya there :wave: this is a kinda sad letter, as I’ll be moving away from rescript. I feel like your recent steps from reasonML to rescript were grave mistakes that took away from what made reasonML special and worth advocating for.

I don’t exactly want to change your mind on these things, as this is your project and if you feel that you’re doing the right thing you should absolutely move forward with it.
However I think that since you’re showing respect towards the community by actually exposing the reasoning behind your decisions I could give you my take on that reasoning, even if I’m just one of many and will probably have no impact on rescript as a whole.

Removal of custom infix operators

From what I understood you’re moving away from custom infix operators because you felt like they increase the complexity of the code.
While I can certainly see what you mean I think it’s a fallacy to assume that the problem lies with custom operators. The amount of custom utility functions that are duplicates and/or neither aptly named nor necessary (because they’re already included in the stdlib or some existing dependency) is staggering. It all boils down to “knowing formalisms”, and custom infix operators are a very handy way to define such concise formalisms. If you know them you can read and write code much faster than without them. Go ask a lawyer or mathematician about how well defined formalisms help them in their everyday life. And yes, that raises the barrier for new programmers but at some point you’ll have to realize that you can’t build an airplane with just a hammer, at some point you’ll have to learn to use complex machinery.
Oh, and underlying that decision with a guy that basically discards every advantage of swift over objective-c as being “fancy new bling-bling” doesn’t exactly help make a point of why people should adopt a new language.

Data-first

There are definitely some nice advantages to this, and yes, I’ve run into one exact problem of data-last every now and then. However…

More straight forward type inference

Yes, definitely nice, but I have to say that I cherished not having to provide unit as a last parameter far more often than I was annoyed by having to explicitly annotate something

Performance

With all due respect, if function calls by themselves are a performance concern I’m not looking at javascript in the first place. To me this is a prime example of a micro optimization.

Transpilate size is a considerable factor… but it probably pales in comparison to the number of apps that still target es6. Latest chrome dev summit has a nice video on this I think.

Concise errors

Oh, definitely useful. However… how many people are using typescript? Have you seen a typescript error in a complex codebase?

I encourage you to set up a typescript project with xstate and pass an invalid object to service.send. Or provoke a situation where bivariance comes into play (react typings hack anyone?). In the best case typescript errors are as straight forward as reasonML errors were and in the worst case they’re plain wrong or misleading.

And how many devs have you seen move away from typescript because of that alone? We still put up with this because “trying around will fix it anyway”. It’s not important to understand the error, only to fix it. Not that I agree with this approach, but convincing someone to learn a new language (no matter how similar, build chain alone is a big point here) based on concise error messages is a really tough sell.

Overall I feel like these moves made rescript more approachable to people that come from an OOP background by defining a way of writing idiomatic rescript that does not enable FP patterns as well as reasonML did.

You can certainly argue that this is a good thing, I’d argue that it enables perpetuation of antipatterns and most importantly it really diminished the incentive to move away from typescript as I think the same patterns that grew because of OOP and are perceived to be “clean code” will now move over to rescript. So if I’m going to have the same conceptual problems with rescript, why would I switch?

That together with the dropping of local open means for me that there is really little sense in advocating moving from typescript to rescript, even if I still think it’s a superior language.
Rescript has just lost its appeal as “something different” that enables a way forward, a way to break with these old habits that are only perpetuated “because that’s how we always did it” and - massively overexaggerated and slightly joking - I’m just waiting for you to introduce the class keyword.

ReasonML enabled me to solve a year-long problem and made me adopt patterns in typescript that are now being seen as extremely useful and “the way to go” by many others at my company, including some hardcore OOP enthusiasts (former Java programmers) and for that I think you deserve huge credit. You reshaped the way people think about functions and react components.

But right now I think that you’ve diminished your advantage (and chance to shape the future of programming) over other languages for something that won’t help the industry in the long term. Sorry for the wall of text and I sincerely hope you’re successful in your endeavour, I’ll be keeping you on my radar.

Love, Katja :heart:

6 Likes

And just to offer some alternative perspectives on each point you mentioned:

Infix Operators
Removing Infix Operator for me is not about complexity - rather the readability of code. I hope to god I don’t have to ever read a library code or teammate’s production that use excessive infix operators. I often have to read code in plain text without an IDE (such as on Github) and if I don’t have go-to definition or hover-definition ready, I can’t see myself ever guess what a piece of code with infix operators does.

Plus, I don’t ever want to have the bike-shedding conversation with my team about whether creating a new infix operator makes sense - naming things with english is already hard and debating about which symbol to use for a function is even more unproductive because its purely based on art/aesthetic.

One of the most popular family of functional programming languages - the Lisp family - doesn’t even have infix operator for built-in math operators! Everything is a s-expression! (* 5 (+ 7 3))

Data/Pipe first
This is a strict improvement over data-last. There is no con here besides not confirming to “other functional programming language’s way” of doing things. Besides, you could always just use a regular pipe by leveraging underscore syntax data |> fn(arg1, arg2, _) with the cost of allocating a new closure. We shouldn’t have to be allocating new closures with no ability to opt-out.

And if we are going to talk about what other FP languages do - what about one of the most recent successful functional programming languages - Elixir and Erlang? They uses data-first convention everywhere and a pipe-first macro. Is Elixir not a real functional programming language then? And is it a big deal because it doesn’t do pipe-last?

Errors
I have been using Typescript at work for 4 years. Type errors created by structural typing and dependent typing features is frequently god awful. In fact I just got stuck on an error message that is as long as the height of my code editor last night. Besides, there are many Typescript developers wanting Nominal typing features since very early https://github.com/Microsoft/Typescript/issues/202.

This is not "real FP"
I observe that a lot of complaints are related to the sentiment that we are “moving away from idiomatic FP”. If this category of issues is why you are moving away, I believe you should think more about your motivation of recommending ReScript to other people in the first place.

As someone who is a FP fan, If I were to introduce ReScript to my colleagues just so I can show them that “FP” is better than “OOP”- I believe that I would be doing a disservice, and it would be net negative value add to other people. How much do I really make their life and project better if I convince them to give ReScript a try?

For me there are very practical reasons for adopting ReScript that improves the quality of shipping products, and I believe there are a few categories of people that we shouldn’t try to convince:

  • People who don’t believe better programming language = better product
  • People who don’t believe static typing = better productivity
  • People who don’t believe out of box performance is important, and everything is “micro-optimization”. This is how you end up with Webpack vs Esbuild and Typesript Compiler vs BuckleScript compiler with orders of magnitude speed difference. If the tool itself is slow out of the box, we developers have little power to make it faster than the baseline.
  • People who believes being a functional programming language is about sticking to the real “FP Language” way of doing things even at the sacrifice of readability and performance - for that I recommend them something like PureScript.

What are in my mind great reasons to adopt ReScript:

  • Javascript and Typescript have run-away feature float. They are getting more and more complex for little value added in the end of the day (and in many ways negative value because they introduced bad patterns). Where as ReScript (OCaml) features are thoughtfully considered before being added. I am happy that ReScript is just not adding everything people want and asks why are these fancy feature better than existing way of doing things.
  • ReScript compiled JS is automatically more performant out of the box due to automatic tail recursive optimization, constant folding, and being tree shaking friendly,
  • ReScript code base is easier to maintain and write due to globally sound type checking and inference, and robust module system.
  • ReScript is extremely fast to compile compare to other compiled languages - which can be directly measured and translated to time and money saved.

I would not recommend ReScript (or any Fancy New Functional Programming language) to try to impose “FP > OOP” ideology onto other people.

16 Likes

Removing custom infix operators

My point was that naming functions with english words will not improve readability over custom infix operators, as when it comes to utility functions they are often not aptly named and can thus be even misleading.

As for the bikeshedding argument: you could easily say to only introduce operators that already exist in the wild, maybe limit that to haskell. Yes, you have to be careful to not overuse custom infix operators, but a warning in the docs would be far more appropriate than outright removing the feature as a whole.

Regarding lisp: and that’s a good thing? “People manage to write code with that” isn’t really an argument.

Data-first

So, let me see if I get this right. Without _ you can’t compose functions as easily and concise as before, and with _ you’re having the same problems as before only with more cognitive load. And all that is done to prevent allocating a new closure? (Which, btw, is an implementation detail of the language)

Sure, allocating a new closure for practically every argument is more expensive, but thinking that without that we’ll achieve “true speed” is an illusion imho. Even with functions of quadratic or cubic complexity that have a significant runtime I have yet to see that allocating the new closure is the bottleneck.

Errors

Apparently I didn’t get my point across, YES typescript errors are god awful, the errors that arise from the situations I mentioned are often plain wrong and have nothing to do with the actual cause. Yet typescript is the undisputed leader when it comes to “transpile-to-javascript” and people aren’t leaving because some other language has concise errors. Why is that?

Nominal Typing

Yes, I often wish for nominal typing in typescript as well, but I don’t want to discuss the typesystem here, because that could imply that I’m advocating for typescript. I’m not, I’m just saying the advantage to be gained by moving to reasonML was more significant than the one that rescript offers…

This is not “real FP”

I’m not saying that. I’m saying reasonML forced me to learn new concepts (that I think are superior to OOP) whereas rescript enables me to carry over bad patterns.

People who don’t believe better programming language = better product

A programming language is still a tool. Tools don’t improve quality on their own.

People who don’t believe out of box performance is important

I have yet to be congratulated on a fast build-chain by management. You’re listing performance improvements of the build chain as something that improves the quality of the shipped product :confused:. Don’t get me wrong, everytime I start a reasonML project I’m in love with the speed of the compiler, but as long as HR gets dictated who to hire based on what’s available on the market and a CTO that is stuck two decades ago DX won’t be a driving factor in the adoption of new languages.

People who believes being a functional programming language is about sticking to the real “FP Language”

Again, ease of composition is my main point of criticism here.

I am happy that ReScript is just not adding everything people want and asks why are these fancy feature better than existing way of doing things

I’m not talking about adding new things, I’m talking about things that were already there and were dropped.

ReScript compiled JS is automatically more performant out of the box due to automatic tail recursive optimization, constant folding, and being tree shaking friendly,

Yes. But current approaches are good enough, typescript devs are easier to find and moving to a new language because later on in the project a performance issue is found is simply laughed at.

ReScript code base is easier to maintain and write due to globally sound type checking and inference, and robust module system.

Yes. One of the points why I still think ReScript is superior to typescript. The outcome of demoing that to my colleagues however was “let’s use these patterns in typescript and enforce them with eslint rules”.

ReScript is extremely fast to compile compare to other compiled languages - which can be directly measured and translated to time and money saved.

Again, DX. “Time and money saved”… I hope every company I’ve worked at is the exception then. We’re spending ~20k€ a year on a system that slows everyone down, but no one wants to take responsibility and change to an available free to use system. There are maven projects out there that take more than an HOUR to compile on a pipeline that is paid by the minute! I’ve calculated what we could save by switching to alternatives so many times now, I’m getting tired of hearing the same old “Wow, that’s great, let’s see what we can do. Next year.”.

try to impose “FP > OOP” ideology onto other people.

I would. Because everytime I got someone on my team to stick to FP principles my job got easier. The thing is, that if I want to sort of “play around with FP” in a “mixed” environment, I already have TypeScript.

2 Likes

Hi @hesxenon, it’s good to hear different perspectives.

I’m a JS dev, never worked before using a FP language but have been learning FP for the past year or so, and currently exploring ReScript.

Personally I related to comments from @sikan, but I understand your comments are about frustrations for your team’s particular preferences.

You post will probably generate some long responses, but obviously ReScript can’t be all things to all people.

I just wanted to share that my experience with ReScript (coming from a non-FP background) has been positive, and the decisions being made by the team, including removing some features, are positives. In fact I would like to applaud the team for the courage to make some of these decisions in the face of some significant criticism at times. I feel these design decisions will actually help me to evangelise ReScript into JS organisations I work at.

I do respect the frustrations you and your team have experienced. I still have a lot to learn, but for me the language design decisions are heading in a positive direction and I will be happy to advocate for ReScript going forward.

13 Likes

Thanks for sharing your perspective. But my experience is completely the opposite :slight_smile: I’ve embraced data-first, and I love the fact that infix operators are discouraged. I haven’t felt that FP is taking a back-seat either.

The one thing that I think is still under-appreciated is that ReScript has become extremely light-weight thanks to the looser JS interop rules.

This lets us write code like document["body"]["appendChild"](..) which can bind to external JS, without us having to spend hours decoding types and creating exhaustive bindings. This makes it very easy to onboard new people into the language, and we don’t really sacrifice safety if we put these calls inside its own module and keep these calls localized.

When I first wrote some serious code with this approach I felt like I was writing in some sort of lispy language.

We’ve (@jcsherin and me) been teaching ReScript to over a dozen univ students recently, and they’ve picked up the language like fish to water. Jacob has been running a metric where about 2 years ago it took a team that we knew, about a year to pick up the language (at the time Reason+BuckleScript), and go to production with it. Later he was able to onboard another team and help them go to production on a non-trivial project in about 6 months. This came down to 3 months for another team later, and now we’ve been able to do that in about a month now. With some further work, we think it can be done in about 2 weeks.

This is a big deal for me because ReScript is a leveller that cuts across educational and economical privilege. A lot of folks who’re doing OCaml learnt it at their university, or worked with colleagues who’ve had that kind of privilege. It is difficult for the average programmer without too much free time or disposable income, to spend the months required to learn and be productive with a Typed Functional Language. I think Elm and ReScript are the only two languages that are helping democratize this paradigm, and ReScript more so than Elm because it embraces the wider JavaScript ecosystem, making it possible for commercial projects to adopt it with less risk.

To me it seems that the language is just picking up steam and is ready to start welcoming a large number of JavaScript/TypeScript programmers. I wanted to say this because I think by definition we hear far more from folks who’re unhappy with something rather than for those whom things work well. I believe there is a large group of happy ReScript users who are silent simply because things work well for them.

20 Likes

Some clarification: custom infix operators have been announced as returning (and I believe local open too). When they land we can scratch those complaints off your list.

However I don’t believe that will solve your wider concerns. Something was announced over the weekend that might appeal to you; I won’t drag that conversation into these forums by talking about it, but it’s out there. If you can’t find it DM me and I’ll send you a link.

2 Likes

The good thing is that for people who like the ReasonML way of doing things ReasonML is still out there. But I greatly appreciate that ReScript is there for developers like myself who are not particularly fond of the Java way of OOP creeping into other languages. But initially I couldn’t really grasp what functional programming brought to the table beyond map-filter-reduce and first-class functions. I tried to like TypeScript but types were just getting in the way and the “any” type seemed to defeat the purpose of using types.

It was actually seeing how types were being used in F# that made we want to start really learning about statically-typed functional languages. I also needed something with good JavaScript interop. I was willing to go with F#/Fable initially simply because there was a lot more material available to help with learning the language as well as functional programming methodology using the language. But then I saw ReasonML and the “syntactic sugar” instantly won me over. I had to leave it alone for a while and when I got back to it I saw the whole BuckleScript/ReScript rebranding drama unfolding.

I guess since I don’t come from an OCaml, Haskell, Scala or other FP background I don’t get a lot of the complaints so I’m not going to pretend that they are not serious issues for some people. But for me ReScript is the perfect gateway drug into statically-typed functional languages. While I like OCaml, I like the fact that ReScript looks a lot like ES20xx JavaScript. It’s possible that as time goes on and I learn more about OCaml (or maybe even Haskell) I’ll want some of those features–but since I work on both ends of the stack I still need good JavaScript interop so can accept sacrificing “power features” for a better experience on the interop front.

I realize that for some it’s not an acceptable sacrifice and I believe that’s okay. ReasonML (or even straight OCaml) is still there to scratch that itch. But as one of the types of developers the ReScript team is trying to reach, I appreciate that they have to make some tough decisions knowing they are going to get a lot of criticism for seeming like they are selling out “the real FPers”. But I for one am appreciative for the option you are providing to give people a statically-typed functional programming language in an even more familiar syntax than ReasonML was.

9 Likes