
ReasonML: Strict, powerful and forgiving - jasim
https://www.harigopal.in/talks/2018/jsfoo
======
thangngoc89
I've been using ReasonML for building complex ReasonReact (React.js binding
for ReasonML) apps. With the strict type system, I can code for hours without
constantly looking at the browser and it just works on first try. I never feel
so happy with coding like that before with Javascript. I would recommend
ReasonML for all Javascript developers. Those ReasonML has some downsides that
need to be addressed: \- Bucklescript constantly releases patch version that
breaks stuff, or removing deprecated functions in a minor version. I believe
for a crucial piece of the ecosystem like Bucklescript, it needs to have a
beta channel so we can test them before official release \- Also, there should
be more communications between core team and developers, I'm scared for the
longevity of the ecosystem. There are no details roadmap of what's coming next
or priority of the open issues. There are many important issues (to me) that
could increase ReasonML like a lot but never get addressed. An example of such
issue would be shipping compiled stdlib in a separate package or have a way
that would allow users to integrate ReasonML to their current node.js
toolchain without waiting for building the compiler on every build (which
could takes more than 3 minutes on slow CI machines)

That been said, I love ReasonML and will continue to invest in its ecosystem.
Shamelessly plug, I built [https://sketch.sh](https://sketch.sh) as a quick
playground for ReasonML and OCaml, check it out if you're interested in trying
ReasonML

~~~
ungzd
Is lack of ad-hoc polymorphism a real issue for such projects? Everyone who
used JS before are accustomed to using overridden methods, or just duck
typing, which are form of ad hoc polymorphism too, but Reason/Ocaml lacks it.
How does this feel? Or it's easy to code avoiding ad-hoc polymorphism after
forming habit for it? Do you use things like function dictionaries to simulate
ad-hoc polymorphism?

~~~
a0
In principle it seems like a significant limitation but in practice it is
rarely an issue.

ReasonML does support parametric polymorphism so it is still possible to write
generic code.

Some language features conveniently help to avoid boilerplate. For example
it’s possible to have a `Float` module with arithmetic operators and “open” it
like this: `Float.(10.0 + 0.5 / 3.0)`.

There’s also a work in progress project called Modular Implicits that will
introduce ad-hoc polymorphism.

~~~
ohadrau
Even then, I feel like working with Floats vs. Ints in a web browser is almost
never an issue. I'd just open Float if I need it because I can't think of any
scenario where I'd use both in one module

------
nouveaux
We chose ReasonML after a previous project of working with JS, React and Flow.
We started using Reason back in May. The plan was to use typescript but after
some great experiences with Rust on personal projects, I really wanted a
language closer to Rust.

Our team loves using Reason and for me, it's been such a breath of fresh air.
Working on front end code is a lot more fun because many of the frustrating
things with JavaScript/React has been removed. The compiler is VERY fast and
the language is well designed.

With that said, the learning curve is a bit much due to the lack of beginner
friendly documentation. If you do not have experience with a ML like language
(Rust, Swift, Scala, OcamL, F#) AND React, I think it will be painful. Despite
that, it is totally worth learning.

The good news is that the core team realizes this and things are changing
fast. React was originally designed for an ML based language and you can see
the stark difference between JS React and ReasonReact. ReasonReact really is
an eye opening experience.

~~~
k__
The whole class component story in Reason felt kinda clunky, but with hooks
this will probably not be a problem anymore.

Compared to the Rust compiler's performance, BuckleScript is a moloch, but as
long as you don't try to run it on a t2.micro it works okay.

~~~
cies
> The whole class component story in Reason felt kinda clunky

See bucklescript-tea for goodbye clunky :)

[https://github.com/OvermindDL1/bucklescript-
tea](https://github.com/OvermindDL1/bucklescript-tea)

~~~
malloryerik
How has Bucklescript-TEA been in your experience? When would you recommend it
and how about JS interop?

For those who don't know, TEA stands for The Elm Architecture, so it's like
Elm for Bucklescript or Reason. The library's author is also very active in
the Elixir community.

~~~
cies
I've only used Elm. I just know of this project, and think it makes sense to
cut out the whole React x-mas tree.

------
ohadrau
Like a ton of other people here, we've been using ReasonML for about half a
year now at Rolltrax [1] and so far I can say I'm ~95% happy with it. I'm a
long-time OCaml user but my co-founder had 0 experience in OCaml when we
decided to make the switch to Reason. I'll just list off some things we've
found using Reason so far:

Positives:

* Really quick to get productive -- the syntax really does do a great job getting new users familiar with the language constructs (I was very skeptical about this before)

* ReasonReact is very nice and works great out of the box

* Writing bindings is generally pretty easy to do, and we're currently maintaining 4 of these (+ 2 existing binding we've contributed to)

* The language and compiler do a great job at working with you to figure out issues

* Everything feels a million times more structured than normal JS code

* Not sure if this is an up-side, but writing code in Reason is so much smoother than other languages that I feel like it's pushed us to implement more client-side features than server-side ones (unfortunately, this means everything depends on a ton of JS)

* Super readable, I feel like I can skim the code and know exactly what it does instantly

Negatives:

* It's still JS, which means you have to deal with a ton of crap from NPM, WebPack, JS's module system, weirdly written libraries that don't do well with bindings, and things breaking in weird ass ways that you can't easily debug... I think this has been the source of 90% of our bugs so far

* Still no way of getting higher-order components working well, specifically with bindings, which makes it really hard to work with libraries like react-grid-layout

* Polymorphism could still be improved. We occasionally get type signatures that should work in theory but can't because of the object system's limitations, which means we have to give up on the type safety and fiddle with Obj.magic or external JS code

* The JSX syntax is still annoying because you can't use spread syntax with a native element (e.g. div), although eventually I'm gonna get tired enough of doing that that I'll open a PR to fix it

Overall, Reason is by far my favorite way of writing web apps. If that's
something you've got to do, give Reason a try. There's still a few pain points
but interop with JS is so simple that it hasn't really slowed us down (except
when webpack breaks lol)

~~~
chickenfries
All of those pain points sound terrible. I want to like Reason and Elm so much
but it seems like the amount of time you have to spend getting these things to
work with other libraries is absurd. Writing JS is not so hard that I would be
more productive in a safer language (beside maybe the very pragmatic
typescript) if you account for all of the extra time spent trying to interop
with other JS libraries or browser APIs.

Elm seemed like it was taking a pragmatic approach with ports but then they
got rid of all of the JS interop code in their package manager, forcing
everyone to write their own glue code.

~~~
ohadrau
To be fair, issues with bindings have really not been too common and when they
appear the fix is just opting out of the strong type checking. 9 times out of
10 when we have a bug the issue is actually something not specific to Reason,
like Webpack making 2 copies of React in the output,

------
nikivi
We chose ReasonML to build the next version of Learn Anything. So far the
experience has been quite pleasant although the ecosystem is still young.

[https://github.com/learn-anything/learn-anything](https://github.com/learn-
anything/learn-anything)

------
chucksmash
Built a small demo project in ReasonML. It was an enjoyable experience.

The generated JS is readable and well-commented when for instance a record is
transformed into an array. Just opening up the generated JS and reading it
made for a nice self-check mechanism when I was starting out with the proof of
concept.

------
kitten_mittens_
Avoiding reason-cli and just using bs-platform and reason-vscode together is
the way to go in this ecosystem.

The problem with reason-cli is that it can get out of sync with the bs-
platform version and fail in unclear ways.

There was quite a bit of pushback against reason at my shop due to the interop
between these two packages and trying to do things like have autocompletion
fail because of them.

It’d be nice if the upgrade of bucklescript to the OCaml 4.6 drops soon too.

~~~
jordwalke
Hi, I work on Reason full time and have been managing the reason-cli releases,
and I'm happy to say that we're pretty close to not needing reason-cli anymore
because the much better alternative is to _avoid_ global installs and instead
model IDE support and as devDependencies of your project. We only have been
releasing a global install (reason-cli) because:

1) Until recently we didn't have better alternatives for BuckleScript based
projects (but then Reason Language Server came along)

2) We didn't have a good way to quickly install per-project dependencies for
the Reason Native workflow. But then we built esy for native workflows which
makes it very fast to install large dependencies across multiple projects by
using a relocatable immutable package build cache.

Now, there's much less reason to use a global install and global installs will
always have the problem of conflicting with project dependencies. I think
you're picking up on that fact. Here's to the sandboxed project future!

This kind of stuff is often discussed in the Discord ReasonML channel so if
you're ever curious to read the pulse on the direction of dev tools, feel free
to join the discussion.

~~~
kitten_mittens_
Thanks for the reply! The Discord channel has been very helpful, but I must
have missed this sort of thing there.

------
jarcane
_So ReasonML is actually a Javascript-like syntax for OCaml, and its tool-
chain converts Reason code to OCaml, which then uses a tool called
Bucklescript to convert that OCaml to Javascript._

All because some people just have to have their curly braces.

I will never stop being angry that this exists. There is no reason for it
other than pedantic bikeshedding and Facebook’s mission to proprietize web
tech. It does nothing but mangle a perfectly readable syntax and bifurcate the
ecosystem of the language.

~~~
int_19h
It's not just about the curly braces - there are many warts about OCaml's
syntax, and some of them go beyond mere niceties, and into the territory of
making it too easy to unintentionally write code that doesn't do what the
author intended. In Reason, it looks like they specifically went after those,
e.g.:

[https://reasonml.github.io/docs/en/comparison-to-
ocaml#patte...](https://reasonml.github.io/docs/en/comparison-to-
ocaml#pattern-matching)

~~~
jarcane
_If Reason uses == to represent OCaml 's =, and uses === to represent OCaml's
==, then how would Reason represent OCaml's === symbol (if it were defined)?
Reason provides a way! "Escape" the triple equals symbol!_

Yes, such a massive improvement to clarity.

Seriously there is nothing here I hadn't internalized within a day of working
with F# or Python. Certainly nothing that justifies forking an entire
alternate syntax.

~~~
int_19h
> Yes, such a massive improvement to clarity.

Given that === is not a standard operator in OCaml, I fail to see the problem
with clarity.

> Certainly nothing that justifies forking an entire alternate syntax.

You do realize that this is very much a subjective judgment, do you? Syntax
_does_ matter. You can argue that it doesn't matter enough to bother, but
that's down to personal taste. Given the popularity that Reason seems to be
enjoying, clearly, syntax is a sore point for enough people.

In any case, I fail to see the problem in general. Reason doesn't fragment the
OCaml ecosystem, really, since it's just a different syntax for the same core
language, and libraries etc remain. It's not any different than all the macro
libraries for Lisps. Nobody is forcing you to use them, and you can still use
a library written in Reason from OCaml, and vice versa. There's no real
fragmentation.

And if Reason ever dies, all code that's written in it could just be converted
to OCaml using the last version of their transpiler, and maintained as such
thereafter.

So, what's the problem?

~~~
jarcane
_Nobody is forcing you to use them, and you can still use a library written in
Reason from OCaml, and vice versa._

You really should go read up about this, because the actual answer is far more
complicated than advertised. Hell, the Ocaml interop section in the official
docs isn't even finished yet.

~~~
int_19h
Most of the complexity seems to be stemming from the JS backend, so far as I
can see, which is not really Reason's fault. What are the OCaml interop issues
when using Reason with the native backend?

------
a0
I used OCaml in production for a 2 years and it was a very pleasant
experience. Recently I started using ReasonML at my team to implement a
Kubernetes configuration tool. It’s surprisingly easy to use ReasonML for
backend development with dune and esy.

------
qwerty456127
I really hope Reason is going to become the №1 mainstream language for React
apps.

------
splintercell
I tried using ReasonML for a blockchain project, and I just couldn't get past
being able to express this logic of interacting with a third party library:

``` const contract = new web3.eth.Contract(ABI, contractAddress, {from}) ```

in ReasonML easily, despite spending hours on trying to figure it out. At the
end I finally reached to a feature request asking to be able to do 'new' on
member functions, and it was in 'planning'.

On the other hand Elm's approach to JS interop seemed to be far superior for
quirks like these. Javascript code lives on the other side of the border, and
Elm code on this. You don't have to create a type for the whole class of the
third party library, just the data you want Elm to manage.

~~~
yawaramin
Can you point to the feature request where you asked for 'new' on member
functions, please? I would like to correct whatever response said it was in
'planning', because it has been doable for a long time now. Here's some sample
Reason that outputs pretty much exactly your above code:

    
    
        module Web3 = {
          module Eth = {
            module Contract = {
              type t;
    
              [@bs.module "web3"] [@bs.scope "eth"] [@bs.new]
              external make: (string, string, {. "from": string}) => t = "Contract";
            };
          };
        };
    
        let contract = Web3.Eth.Contract.make("ABI", "contactAddress", {"from": "from"});
    

You can try it out in the interactive playground.

Also, regarding this:

> You don't have to create a type for the whole class of the third party
> library, just the data you want Elm to manage.

That's exactly how Reason JavaScript bindings work too.

~~~
splintercell
Just to be clear (and I now remember more details), I wanted to do bs.new with
bs.send, but it wouldn't work.

I am going to try what you suggested, but keep in mind I did go to the slack
channel and tried asking this, none of their solutions looked like yours.
Either way, intuitively @bs.new and @bs.send should be able to work together.

[https://github.com/BuckleScript/bucklescript/issues/2659](https://github.com/BuckleScript/bucklescript/issues/2659)

~~~
yawaramin
I see your problem (which is btw quite different from your original comment
;-) ). In a statically-typed language like Reason it's difficult to model
dynamically-generated types like `hello_proto.Greeter`. One way is to use a
functor (
[https://v1.realworldocaml.org/v1/en/html/functors.html](https://v1.realworldocaml.org/v1/en/html/functors.html)
) but they have their limitations. This is why we have things like graphql_ppx
which is a compiler extension to _generate types from GraphQL schemas_ at
compile-time. You'd need something like this (or, easier, a ReasonML-targeting
gRPC/Protobuf client generator) to solve the issue brought up in GitHub.

------
jorblumesea
Doesn't typescript also have variants and similar variant checking? Maybe not
understanding what the big deal here is...

[https://www.typescriptlang.org/docs/handbook/advanced-
types....](https://www.typescriptlang.org/docs/handbook/advanced-types.html)

~~~
ohadrau
For me, Reason's type system seems a lot more focused on what it's trying to
do. It's much more minimal than TypeScript's, so you don't end up trying to
hack it to fit weird JS types. This also means you get full type inference
which is huge.

The other nice things are the fact that it's not backwards compatible with JS
so a lot of the syntax is a little more convenient and the module system +
object system are the same really powerful ones that OCaml has. Plus, the
entire paradigm of the language is so different that it totally changes the
way you use React (I remember having all kinds of issues my first time trying
to use React just because of how weird some functional stuff is to do in JS,
whereas in Reason virtually any program that typechecks is 100% valid for
React).

------
smnplk
Does anyone have experience with Clojurescript and ReasonML?

~~~
thetophs
I used both a fair amount. I liked both languages quite a bit, but I always
found the tooling around Clojurescript difficult to use. ReasonML was a much
better experience for me. After using both I think I personally prefer the
experience of using a typed language over a dynamic language. This was from
the perspective of making UIs with React.

------
chrisweekly
In the context of developing React webapps, what advantages obtain from
ReasonML over TypeScript?

~~~
skosch
I've worked with both.

Typescript is (and feels) bolted-on, and can fail in dozens of ways.
ReasonML's type checker is 100% airtight. It also has pattern matching and
piping, to help make your code more concise.

Typescript is easy: it's just ES6. ReasonML is (and feels) very much
unpolished. Conflicts and overlaps between ReasonML's and Bucklescript's and
JS's standard libraries, poor documentation, very flexible but very
unintuitive JS interop syntax, frequent updates that break your code, etc.

One big advantage is that ReasonML's compiler is lighting fast. As in, it
compiles a big project in an instant. I don't know how it works behind the
scenes, but the sheer speed changes how you develop. With JS/TS, you hit save,
wait a few seconds for the iterative recompilation, refresh your browser,
check your work. With Reason, you code, hit save, immediately get a helpful
error message, rinse and repeat, and eventually you open up your browser and
everything works 100%. It's pretty cool.

~~~
h1d
What could be the fastest way to recompile TypeScript that also monitors for
file addition and deletion?

So far I'm having a decent experience with pm2 monitoring for any changes or
additions of files to restart a ts-node instance but it does make you wait a
few seconds or else nginx throws a 502 when the ts-node is still restarting.

~~~
chrisweekly
Some projects use Babel for everything, including ts->js transpilation. If you
go that route (vs using tsc), it may make it more straightfwd to leverage
watch, along w/ the rest of the robust babel and webpack tooling that's
available. /$0.02

------
qwerty456127
BTW does Reason offer a solution for decimal the decimal precision problem
there is in JavaScript?

------
sofimorales1987
Nice! Thanks for sharing.

