ReasonML: Strict, powerful and forgiving
harigopal.in
harigopal.in
That been said, I love ReasonML and will continue to invest in its ecosystem. Shamelessly plug, I built https://sketch.sh as a quick playground for ReasonML and OCaml, check it out if you're interested in trying ReasonML
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.
http://dev.realworldocaml.org/classes.html#virtual-classes-a...
Now, you can't downcast or cross-cast or do a runtime typecheck easily, but that doesn't mean it's impossible - you just have to use roundabout ways like variants to do so (which also means that you can control which class hierarchies it is available for, and which ones it's not). A class hierarchy combined with an polymorphic variant type to allow runtime type queries can be made as powerful as a runtime typecheck/cast in Java - if more verbose - for those rare cases where you actually need it.
http://dev.realworldocaml.org/variants.html#polymorphic-vari...
Of course, in practice, most cases where you'd use a downcast or a typecheck in a language like Java, map more naturally to regular variants and matching on them in OCaml.
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.
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.
See bucklescript-tea for goodbye clunky :)
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.
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)
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.
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.
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.
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.
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.
https://reasonml.github.io/docs/en/comparison-to-ocaml#patte...
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.
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?
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.
But this code does not compile. Even if you do not use https://github.com/ocaml/merlin you will always realize it at compile time. What type is y supposed to be to pass compilation?
People still complain about it, but somehow, it became one of the most popular languages on the planet.
And how is it welcoming to newcomers to essentially be upfront asking them "right, now which syntax will you use?"
Unless the answer of course is just to nudge them all in the direction of the one owned by a massive corporation with more money than some countries ...
And all because some people are allegedly pathologically incapable of understanding a language without bolting curly braces on it.
It's the most absurd overcorrection for a pedantic complaint I've ever seen in tech.
Facebook already uses OCaml.
My understanding is that it can be translated both ways with no difference of semantics.
``` 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.
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.
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.
For those not familiar with Elm it means you basically have to interact with all JS code through a pub-sub model and can't ever directly call JS code.
Elm's creator has his reasons for why he does this (https://guide.elm-lang.org/interop/ports.html), but it can make calling JS from Elm quite a pain.
I do the same thing in Elm, but all that code is living in a JS file, and it can be in Typescript/whatever.
https://www.typescriptlang.org/docs/handbook/advanced-types....
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).
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.
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.