Good arguments for using ReasonML instead of Typescript?


#1

Hello,

What are some good arguments to use when pitching ReasonML contra Typescript? ReasonML is a lot more elegant, variants are much cleaner than disjoint unions. However this is not really enough to convince someone to pick a much smaller ecosystem. Features like GADTs and polymorphic variants are really handy if you understand them but if someone is new to the language, why would he/she care?

How should I go about convincing a team to use Reason instead of Typescript if they are evaluating those two options?


#2

Perhaps the best way to see the benefits of Reason is to use TypeScript for a bit :slight_smile:

More seriously, I’ve written some thoughts on TypeScript’s approach to JavaScript static typing, versus Reason’s, here https://dev.to/yawaramin/typing-and-code-flow-in-typescript-and-reasonml-2paj

But here are a few more bullet points (comparative to TypeScript):

  • Type system with soundness guarantee
  • Super-fast compiler
  • Powerful module system with all sorts of benefits, e.g. opaque types (i.e. newtypes), functors enabling higher-kinded types, enforced modularity especially with non-recursive modules by default (i.e. module A can’t refer to anything in module B if B refers to anything in A. This might sound annoying initially but is actually a godsend for maintaining a comprehensible codebase over time.)
  • Module system again: no need for annoying ‘wall of imports’ at the top of every file, just immediately use the modules you want in any file in your project. For better structuring try the guidelines here https://dev.to/yawaramin/a-modular-ocaml-project-structure-1ikd
  • Actual deprecation and tail-call annotations for code so you can evolve a codebase over time, and warn if a recursive algorithm is incorrectly implemented
  • Warnings can be made fatal to enforce better and more careful code style in a project, a big win for comprehension and safety https://dev.to/yawaramin/ocaml-reasonml-best-practice-warnings-and-errors-4mkm
  • BuckleScript compiler actually does constant folding for you, i.e. it just optimizes away anything it can evaluate at compile time. Code output tends to be smaller

EDIT: another important warning:

  • Warn on unused values. Very important for keeping a codebase neat and tidy over time

#3

Inference and ergonomics is the primary selling point for me. 100% soundness with a fraction of the annotations TS forces you to write is a big thing imo. Also, it feels like the language is much smaller and more restricted, which I think is a good thing.

But I also think it’s important to be clear about Reason being quite different to TS/JS, especially if your team consists of JS developers with little or no experience with other languages like Reason. I’ve had bad experiences with people expecting “just a bit stricter TS” when in fact the difference is quite large.


#4

Yeah. It’s even possible that its JS-like syntax is doing Reason a bit of a disservice because some people expect it to work just like Javascript, whereas a significant portion of OCaml semantics is quite different (and also, I like the look of hd::tl better :grin:).


#5

Yeah, I really agree with the syntax similarity doing Reason a disservice. It really threw me off in the beginning. I was trying to do things the JavaScript way, but needless to say I had very little success :smiley:

But for the type of developer who appreciates and sees great value in type safety, a compiler that does not let you ship bugs, and the ergonomics of a language, ReasonML is just plain awesome. To me it just makes so much sense and the positives outweigh the negatives by far.


#6

The great thing about ReasonML is that you can write straight OCaml syntax code in any Reason project if you want. E.g. bucklescript-tea provides a very Elm-like developer experience, thanks in part to the DSL-like OCaml syntax for creating virtual DOM nodes.


#9

Well, it probably wasn’t that bad for me, since I’ve read a bit of Real World OCaml and did some exercises at Excersism before starting with Reason syntax. And anyway, whichever way you learn that difference, when you did learn it, Reason is plain great :+1:

I have too little experience yet to tell wether switching between OCaml syntax and Reason syntax in the same project is too much cognitive overhead. Besides, even for modules without any ffi, I’m beginning to like Reason syntax for the autoformatting. I find OCaml autoformatting too dense: in comparison, autoformatted Elm has much more air.

As for TEA, what’s your sense of TEA in OCaml? What I mean is, Elm is the purest functional language I know where effects are declared by reducers and implemented by the framework. By contrast, OCaml is able to set state and dispatch actions imperatively, just as it was done in React since before Reason. Do we need TEA?


#10

I find that people can get used to any syntax after a while. Syntax doesn’t really matter. Providing a syntax choice is mainly done to onboard people as gently as possible.

Yes :slight_smile: Or at least, the people who are using it in production need it. To my mind it very effectively demonstrates that OCaml/BuckleScript is fully a superset of Elm. Regarding effects, it doesn’t really matter too much. We are moving towards a pure-in-impure approach nowadays in a lot of languages, even in libs like React with hooks. It’s always better to have that brute power and not need it, than to need it and not have it.


#11

The TEA (and other dataflow styles) is to remove imperative hard-to-follow code paths, it makes everything reasonable and simple to follow, which makes maintenance significantly easier than things like (non-functional) react.


#12

Great question :slight_smile:

These are some questions i ask myself, with some side notes for each:

  • Can you afford/be bothered with the time cost of writing bindings?

    • TS has come a long way in terms of authors shipping declarations with their JS, and the DefinitelyTyped repo.
      • I rarely need to write TS bindings/declarations.
    • Reason is getting better though, so if you’re starting a new project after some time why not see its progress? https://redex.github.io/
  • Can you sacrifice some of the IDE experience to use Reason? TS wins here imo

    • Caveat with TS though: It can be painfully slow at times in a very large project, especially a multi project monorepo. It’s getting better though.
  • How willing and able to use reason is your team?

    • What matters most (imo) is the productivity and happiness of your team. Its one thing for them to not be open to new ideas, but it’s another to reject their perception after they’ve honestly evaluated it.
  • How scalable and maintainable do you need your project to be?

    • Use reason if this is high, for a number of reasons which other people in this thread i think have answered.
      • Key points for me?
        • Module system
        • Type system soundness and awesomeness
        • Super fast compiler
        • High quality ecosystem (vs high quantity in JS+TS case)
    • Another thing around scalability for me:
      • If you can afford to convert a JS library to TS or reason, do it. A JS project that has separately maintained TS or Reason bindings is good in the short term but not good in the long run.
      • This also contributes back to the community if thats your flavour
  • Some other reasons to choose reason over TS:

    • TS’s story is still a bit like: “add types to your javascript”

      • albeit it has come a long way.
      • The point here is that there is still a massive disconnect between JS, build systems, and types. Take for example babel macros and webpack loaders. Each cause very non-trivial differences to the logic and types of your code. TS has no mechanism of knowing about them. I guess you have the same issue in Reason + Babel + Webpack, however you can write a PPX, and the community is making more of them.
    • Cross platform development story

    • It is highly likely that one day OCaml/RE will be able to target WASM, once core issues have been nutted out like GC

    • Macros and PPXes

      • Endless possibilities of extensible and typesafe language features, instead of babel macros which are not type safe to my knowledge.
    • https://github.com/apollographql/reason-apollo

      • Good demonstration of an awesome PPX
    • https://esy.sh/ - Jordwalke cares about native

    • Hopefully one day a unified build system between Dune and Bucklescript projects

    • Generate TS + Flow definitions of your reason code for type-safe (one way) interop.

    • The core type system doesn’t change often because its awesome.

      • Overlooked a lot. New TS versions with more features and changes come out very often, which tend to break older code, which cause you to not upgrade.
    • Learning about the caveats of TS takes a long time if you’re on your own and never experienced a sound type system.

      • Things like:
        • const myInstance = inversify.get<MyClass>("instanceKey")
        • const foo = bar as MyType
        • Not having strict mode in tsconfig
        • Each above give a false sense of security

So much to unpack sorry!
Hope this helps :slight_smile:
Please point out anything i’ve got wrong or if i’m misguided anywhere!


#13

Does anyone have some good arguments for using TS over ReasonML?


#14

For us a big part was that we were constantly running in to compile-speed issues using TypeScript. If you’re having similar issues, that was a big part of getting people to agree on giving Reason a try.

TypeScript’s m(any) “escape-hatches” and need for explicitness was definitely also a factor.

Pattern matching, variants and other language-specific goodies also play a big part of course, but features aren’t always as helpful as arguments like speed. :slight_smile:

YMMV!


#15
  • Better IDE support. From code navigation to running individual tests or groups to refactoring intentions (say, in WebStorm)
  • Easier to hire devs
  • Easier to find help: more answers, more articles etc.
  • Easier to grok by someone not familiar with ML languages or FP in general
  • Probably more trivial to introduce to an existing codebase
  • Almost all typings are readily available
  • Future-proof? I mean, ReasonML destiny still seems more precarious