Reason 3
reasonml.github.io
reasonml.github.io
That's truly amazing.
Interesting how Elm is inspiring other frameworks and languages. First Redux and now Reason's error messages.
Sounds like an amazing accomplishment for the Messenger team.
The JS part of messenger.com bugs a lot more.
I could write a 100-page essay on all the ways the web-version of messenger fails in subtle and not so-subtle ways, and how it cannot keep the pace of development with the mobile version.
The dev team hasn't received bug reports though. Must be nice.
The fact that your code doesn’t break in production doesn’t mean it’s behavior is correct.
- messenger.com is a subpar experience compared to mobile
- there are multiple behavior issues:
— it fails to reconnect when connection is lost
— it randomly fails to unfurl urls which display correctly on mobile
- it may unfurl a url in one chat and not unfurl the same url in another chat
- it may lose connection and not even notify about it (mobile chat updates, web chat doesn’t, reloading helps)
- try searching. good luck discovering where “load previous” is hidden
- it may get stuck in a scroll position displaying an old message at the bottom of the chat
Shall I continue? I use messenger.com exclusively throughout the day. Your pride in “not receiving bug reports” for the Reason code doesn’t amuse me.
chenglou is doing a bit of massaging of the numbers; the claim that there's "only been 10 bugs" isn't quite true. Their code base is 50% ReasonML and 50% JS, and in the ReasonML portion, they've only had 10 bugs - a signification reduction! But they haven't commented on how many bugs are reported in the JS side; we can probably infer that there is many more (since the implication is that there were many more bugs in the old JS code they replaced).
You seem to be frustrated that the messenger.com experience is not up to par and have latched on to the idea that, since the team says they're seeing improvements since introducing ReasonML, that they think they're perfect now. I guarantee you that's not the case.
It sounds like you have some very valid complaints, though, and as a daily user I bet they'd love to hear your feedback. So maybe fill out a bug report with what you just wrote? :)
I started using the Reason syntax, but soon ended up migrating my project to vanilla OCaml as I found the syntax less JavaScript-like and easier to follow when thinking functionally vs imperatively. Also, there are many more tutorials out there (currently) for OCaml than there are for the Reason syntax.
As I understand it the two syntaxes are pretty much interchangeable, both use the same underlying AST, the same compile-to-JS backend (Bucklescript) and can even be auto-converted using `refmt`.
Also, if it's important to you, only the Reason project seems to still be encumbered by Facebook's patent grant, while the Bucklescript project was originally started by Bloomberg and now seems to be an independent project without the additional patent clause.
Both projects are really exciting as a practical way to bring type safety into the browser, with ridiculously fast compile times and tiny bundles.
You can put in Reason or OCaml and it will spit out the other. I used it to work through Real World OCaml in Reason.
let make ::message ::extraGreeting=? _children => ...
let make = (~message, ~extraGreeting=?, _children) => ...
Plain OCaml: let make ~message ?extraGreeting _children = ...
Fortunately bucklescript is a completely separate project. After this change I might ditch Reason and just write OCaml. There were some little improvements with Reason vs OCaml but now OCaml appears to be a clear winner!BuckleScript's author and I collaborate on a daily basis, btw. So you're definitely welcome to use _just_ BuckleScript. I'm not too sure your reaction is genuine happiness for vanilla OCaml, but if it really is, then our mission's accomplished (https://reasonml.github.io/guide/what-and-why#why-reason). If not, sorry about that.
F# has embraced the OCaml syntax while at the same time cleaning out many of the warts (+., do end etc.). It also now has good tooling available on all platforms.
Despite being a full time javascript/typescript developer I find F# syntax much more appealing and easy to grok than Reason's js inspired syntax.
[1] http://fable.io
Unfortunately, it also drops my favorite thing about OCaml, which is the module system.
I also like that there are different operators for ints and floats. It makes it very clear when you've accidentally mixed the two.
The different operators are a concise way to tell the type-checker that you're working with floats.
Of course, F# has not always been the favorite lovechild of MS, but the OCaml ecosystem does not seem to be in a particularly stellar state either.
From an individual standpoint, there are some unique aspects of OCaml that we like a lot. The properties of BuckleScript for example (tiny output, great js interop, fast simple compilation).
No doubt that the ecosystem could be improved, but that's what we're here for and what we're willing to do.
Maybe that's a good thing for Facebook?
I'm not entirely sure what you're referring to, but OCaml has been around and used for real work for much longer than F#. I'm not sure it's so clear cut.
Since it's all JS under the hood, the type system is an illusion that language plays tricks on you. This makes it hard for people to understand how JS works or functions; without prior knowledge. Just to quote example one of my team mate had an interface in Typescript, and he was not able to understand why cant he do `x instanceof Foo`. Long story short is you can't have good "Typescript" programmer without being good JS developer. Which I believe will be the case here too. Yes it makes auto-complete better and documents really well; but improves code is debatable.
Don't get me wrong; I am not against it. All I am mentioning is the flip side that nobody will mention. OCaml is really powerful and cool kids are going to experience it with this effort, may be bring in new features/inspiration for next ES. But IMHO just a transpiled language can give you better constructs to express code; but it can't prevent a dumb programmer from making errors. I will for sure give this a shot and blog about it.
Transpiled/compiled/whatever you want to call it, the type system can prevent dumb and smart programmers from making a whole class of errors. In my experience OCaml has prevented so many errors I would have made in JavaScript, including but not limited to:
- Non-exhaustive select/case statements - missing one of the possibilities causes undefined behaviour. It might not even be a case of carelessness or forgetting - just that a new option gets added by someone unfamiliar with the codebase and doesn't realize they need to update a bunch of select statements.
- Changing the name of a field on an object across the codebase, and forgetting to update every single instance. OCaml won't even compile until you've fixed them all.
- Null and undefined weirdness. Just search any large JS github repo for "null"/"undefined" and see how many issues are related. With OCaml, you'll almost never see them because you're forced the deal with the possibility before your code will even compile.
I believe that a type checker isn't necessary until you can no longer hold the entire codebase in your head. For me, that means once my program goes over about 150 LOC, I need the compiler to help me out.
TS is, among other things, JS plus type annotations, but it also relies on the same underlying type system as JS, and TS types, as I understand it, are completely erased at runtime. For example, interfaces don't exist in JS, and classes are prototype-based. So it inherits those flaws, and doesn't patch over them with some kind of runtime, and you end up with a leaky abstraction.
I don't know anything about Reason's JS interaction to say if it's similarly leaky.
For each object, there is some function that takes no input and returns that object, by simply constructing the recursion-free parts of the object graph and then filling in any cycles. (TypeScript allows mutation, right?)
Then the question of `x instanceof Foo` becomes "is the function returning x typeable as () -> Foo". Of course that check is going to be much much more expensive than the simple comparison of the class tag other languages use, so I can understand why it's not part of the language.
function () { return {field: "value"}; }
produces a value of type Foo precisely when the original object was of type Foo, even if the code producing it was much more complex.I don't see why that wouldn't work. If you have a specific example where that approach fails, I'd like to know about it.
Doing this in the general case, I assume, is probably not practical.
OCaml looks rather foreign to the regular JS dev and the last versions of Reason looked more like JS, but still had a few strange parts.
Reason's creator also created ReactJS, whose first prototypes were written in SML,
a distant cousin of OCaml. We've transcribed ReactML into ReactJS for wide adoption.[0]
[0] https://reasonml.github.io/guide/what-and-why/To fix the problem, a couple people from various parts of Facebook got together and started building/testing Reason together, and eventually we shipped what is likely the largest (in terms of machines (billions)) OCaml deployment ever via Reason React.
There’s still many pieces of OCaml beyond syntax that should be improved and we would like to continue fixing all the blockers to adoption that we can. Thankfully the rest of the OCaml community has the same goal and are doing great things at deeper parts of the toolchain and compiler. Our story started from the UI use case so our work and messaging so far has centered around it.
This is a perspective I wish was more prevalent in the programming community.
1) It is not compatible with advanced optimizations in Google Closure's compilation process.
2) I've been burned by less than ideal implementations of immutable data structures for functional programming in the past, particularly in Elm. I haven't done enough with Immutable-Re to know if it has similar issues, but all functional data structures are not created the same. I'm spoiled by ClojureScript's implementation which has never thrown a stack overflow error for me, unlike Elm. In Elm, if you have a list that gets too large, you have to manually break it up into different lists and do weird concatenation stuff that is quite clunky because somehow it's not doing structural sharing quite right to ensure these things are transparent under the hood. Experienced Elm users helped explain this to me, and it's not something I like to think about when writing in a functional style.
So I've been a bit hesitant to embrace just any functional programming language for serious enterprise work. But I'm very intrigued by Reason and Bucklescript and am keeping a very close eye on them. I probably won't do more than toy projects in them any time soon, but it would be great to someday.
To clarify, for anyone who comes across this later: there was a bug in the Elm 0.18 compiler that was triggered by enormous list literals. (Hence the workaround of concatenating smaller literals.) Nothing to do with the data structure itself.
After all, it's a singly linked list; there's not a whole lot of variation in how those are implemented. ;)
I've read that it has both List and Array, yet neither appears to be ideal for proper functional programming; List, as you say, is a linked list, yet it is recommended [0] over Array for functional operations like map, fold, etc -- but you wouldn't normally want linked lists for that sort of thing, esp. if your maps and folds were part of a larger data transformation of composed functions. Does Elm offer anything similar to the structure of ClojureScript's persistent vector?
I have learned that FP without the guts of serious persistent structures is not so good in practice.
[0] https://stackoverflow.com/questions/37707577/array-vs-list-i...
Closure Advanced has many benefits so it's really nice to support it, especially if you're writing a whole site app of decent size all in one codebase.
Also I’m still hoping for an async/await équivalent. I’d love to use Reason for Node API stuff but the JS interop with promises isn’t very pretty...
That seems like a pretty big downside.
The JS world has this in Immutable.js, which provides a set of persistent data structures that are excellent by any measure. However, since it's not the default data structures provided by the language, practically no third party library actually consumes/emits them as input/output directly.
What this means in practice is that most of the performance benefits of structural sharing through Immutable.js ends up being outright negated many-times fold by the necessity to recursively convert to and from JS native collections at the edges of your system that inevitably needs to call out to/consume data from third party libraries. Not to mention that the developer ergonomics of working with Immutable.js pales in comparison with that of native JS collections, since you're limited to the traversal and manipulation APIs provided by the library, and have to forgo excellent functional utility libraries like Ramda [1], and handy language features like destructuring and spread.
This is why even in systems that embrace immutability like Redux, the prospect of using Immutable.js comes with a huge list of caveats that are well documented [2], driving most developers to end up choosing JS native collections and doing naive copy-on-write without structural sharing across the board.
[2] http://redux.js.org/docs/recipes/UsingImmutableJS.html
In contrast, in the ClojureScript ecosystem, everything uses the default persistent collections, and so this is never a problem.
"Why the PureScript community uses Bower" explains why Bower was chosen: http://harry.garrood.me/blog/purescript-why-bower/
I don't understand why Bower is such a sticking point for people. It works perfectly fine for PureScript and (as the article explains) was the right tool for the job.
Any word of when this will be supported/promoted officially? Just got this response from one of my former JS colleagues: https://twitter.com/keirasaid/status/924169973878046721 - it's pretty hard to convince JS developers to use something that is still recommends using Bower for package management. :/
psc-package does* very much look like it's going to be the "sanctioned/endorses/semi-official" tooling for pkg-mgmt one way or the other.
This popped up just now in my feed reader: https://qiita.com/kimagure/items/0d9354900d7a7dbd3864
But the thing to realize is that this syntax change isn't for folks and you and me. We'll be fine with either.
Did you consider having a 'beginner mode' Reason, then flipping a switch to compare it to compare it to the non-parened version is?
Don't take my words for it: https://github.com/facebook/reason/pull/1299#issuecomment-30... https://realworldocaml.org/v1/en/html/imperative-programming... https://drup.github.io/2016/08/02/difflists/ https://bucklescript.github.io/bucklescript/Manual.html#_cal...
I'm jumping into this conversation early on because too often this point is raised and turns into an uncharitable interpretation of our motivations, e.g. "look at these js programmers, not understanding the beauty of currying". Rest assured that we do (and that we're not just js programmers), and that the Merlin and BuckleScript authors know very well what they're doing. Hope this clarifies things a bit.
Interesting about argument syntax + effects. I've mainly used currying in pure languages. Is it about accidentally calling an effectful function multiple times? Is the idea here that you are conservatively treating everything as effectful with the uncurried syntax (before algebraic effects land), then will make pure stuff curried in order to attract people to use pure functions where possible?
I still can't get my head around why it would be an optimization problem too, seeing as it would be most using the same underlying AST. Unless they actually translate the pseudo-parameter lists into actual tuples in the parser, forbidding raw, single argument passing. :/
Not sure what optimisation problem you're referring to, Reason and OCaml underlying AST are exactly the same. There are no actual tuples unless the programmer is creating actual tuples.
Reason does not solve these, they're problems inherent to the underlying language and the choices made. I think the point being made was just that currying isn't a clear step forward, but causes some problems as well.
_This_, I do think, is a fair argument. It's indeed an accidental drawback of the syntax revamp. Though there are very realistic way to prevent the confusion: https://github.com/reasonml-community/error-message-improvem...
Regarding optimization: see the BuckleScript link on explicit uncurrying. The impact is very visible: the compiler analysis for specializing for uncurrying best-effort, and when it bails, it looks like this: https://reasonml.github.io/try/?reason=PQKgBA5g9lAmYGMCGBnAp... which calls https://github.com/BuckleScript/bucklescript/blob/2a66960b5a.... How many function calls did your curried call just turn into, in the second case?
Unless you introspect the output (which is actually viable to do in a compiler with clean output, such as BuckleScript), you wouldn't know that your higher-order function accidentally became pretty much 4+ calls instead of one. Now imagine quadrupling every high-order function calls or so. BucklesScript (and native OCaml) do a crazy good job of avoiding this when possible, more so than most, as shown in the snippet's first scenario; the manual even shows guaranteed uncurry if you put the right annotation. But if you want to take advantage of _that_ (and please do), there are other tradeoffs as well, but I digress. In general, the compiled code's speed is as good as you can get for JS output.
The perf point alone is not a pedantic argument as you can see. And you might start wondering about other languages' output for currying. Regarding your other comment: yes, from a typing perspective, currying indeed works out wonderfully for pure languages like Elm and PureScript. But OCaml's not a pure language; we've made other tradeoffs; and context matters.
Not sure about your comment about the AST, but I think you're saying that the situation doesn't get better/worse in the new syntax: this is true, since the syntax revamp is really just that: a syntax change. Which is why I said earlier that I was arguing beside the point. But currying seems to attract so much unbalanced attention in this context that I felt I should address it so that it doesn't overwhelm the rest of the syntax change's purpose. Looking at the rest of the threads, it still did, but I'm glad your reaction has been doubt rather than unreasoned negativity, so thanks for that.
Can you explain this? Currying and side-effects seem orthogonal to me.
I agree though. Honestly, getting worked up over such fluff as where parens go, which whitespace to use, what line curly braces go on is a minor annoyance of mine. The human brain is capable of parsing some pretty obscure stuff (see: human language) just fine.
Same goes for a lot of Haskell code.
"A lot", not "all": yeah indeed at least you can tweak the punctuation towards more ergonomic (aka more productive) aesthetics. What you describe is just the unfortunate result of many-perhaps-most (early) Haskellers / the std-lib authors being married to established-but-ugly academic operator symbols instead of boldly redesigning them for green-field programmers of this (then, newly from-scratch) programming language.
Once swapping out the built-in `.` for <. and `>>>` for .> and $ for <| and & for |> it all comes a breeze to read (I mean, in comparison), about on par with Elm/F#. Now I've never heard anyone complain that Elm code is unreadable, it's a good example for other MLs to follow.
The rest of what you describe is just due to these hackers being heavily into their own combinator libraries, truly if you code all day, just as there shouldn't be a need to elaborately spell out "function" and "return" and so forth all the time in imperative, they feel less need to spell out all the map/filter/reduce English words all the time. At some point, all the names describe "symbolic relations of sorts" and I wouldn't fault anyone for philosophizing: "that which is specific to my program should be named as words, but that which is 'primitive' / generalized / commonly used among all sorts of programs could just as well be just symbols" ;)
I mean I hack in Go all days right now and it's fun --- lots of parens & braces don't exactly kill me. Here, tweaking one's colour scheme easily solves this in one fell swoop and takes just under a minute tops. No need to go "ML-ish FP" just for the lack of curlies. =)
I must admit that if my compiler reported errors like this it would start to grate pretty quickly. Besides, isn't a bug exclusively something that breaks at runtime?
E: s/big/bug/
Every Python exception tells you
> Traceback (most recent call last):
Which is a similar boilerplate statement. Except less useful to newcomers.
And if you doubt the need for newcomers to understand that stack traces and compiler errors are useful, then take a look at new user questions on StackOverflow - it's incredible how many of them flat out don't include that information. This kind of thing makes it way more likely the user recognises this is something useful, and better than that - makes it way more likely they can apply that information and solve their own problem.
> Besides, isn't a bug exclusively something that breaks at runtime?
I mean, it would be a bug if the type checker hadn't caught it. The runtime distinction seems completely arbitrary when we are talking about tools take take runtime errors and make them impossible.
Once you’re more experienced with the language, you’re typically using your editor to handle the error checking, so the extra “noise” is ignored in the parsing of it.
Elm's and Reason's approach let even the experienced dev get to the root of the problem immediately.
Thanks for your work folks, ReasonML is just getting started.
We'll try to make it into a proper compiler plugin, but it's not trivial right now
([@JSX] div(~foo=bar, ~children=[child1, child2], ()));
Or a preprocessor that'll give you a JSX-like syntax, but without the type checking: https://github.com/cxa/ppx_bsxHowever, unfinished patches cannot be merged into our mainline tree, and this PR https://github.com/ocaml/ocaml/pull/102 needs some attention to rebase it to trunk, and also to get feedback from testers who may have tried the opam switch and have comments. (associated writeup https://arxiv.org/abs/1512.01897)
Help welcome on this particular patch, and other newer ones from Reason that can be ported over to OCaml and submitted as normal feature improvements.
By the way, the above patch is different from the one that ReasonML uses. Realistically, the work done by the Reason team is more recent and actually shipped with the BuckleScript platform, so now the blocker is, which direction does the OCaml compiler want to go in.
Thats funny.
In short, every part works, but the workflow is a bit contorted atm
Reason has a much faster compiler, efficient immutable operations, and is built using tried-and-true tech (OCaml).
rm /home/pc/node/lib/node_modules/bs-platform/bin/refmt.exe
ln -s /home/pc/node/bin/refmt /home/pc/node/lib/node_modules/bs-platform/bin/refmt.exe
Is there no source map support? Also: I have to set up requirejs myself to make Reason code work in the browser? Not only that, it doesnt seem like the whole "each file is a module" system is actually codified in the output. I see no require calls that would indicate the right loading order for my generated .js files.
Generated code has weird comments in it like /* Facebook / and / Instagram */
Can you give an example of 'I see no require calls'? Require or import calls should be generated correctly.
Yes, I forgot about bundling, sorry, but if you are in debug mode you're not minifying the bundle JS anyway so whatever you're looking at should still look a fair bit like the input Reason, especially because the names are only minimally mangled.
After, it's about a convenience easy way to compile your Reason code with an OCaml code. Reason is just a preprocessing, you should use the `-pp` option with /your favorite build system in OCaml/ and, I think, it's enough.
Thanks for the answer; the other comment alluding to support being recent and the lack of information had me a bit worried. I guess the lack of information is because it just works ;)
(I know there's going to be some overlap between project naming, but Reason is a fairly well-known product...)
Not https://www.reasonco.com/ that appears to sell hardware.
or other 'reason' initiatives.
I have been a programmer for as long as I have been a musician, but strangely, never heard of ReasonML until now!
I do find it ironic that in their announcement, they don't even try to defend the decision, but instead say, effectively, "if you don't like this change, you're just bikeshedding", and "if you don't care about syntax, great!" Given that the entire purpose of Reason is one giant bikeshed about OCaml syntax, this reads as hypocritical.
They also say, effectively, "no complaining in public allowed, just PM us (so we don't have to have a real conversation and we can ignore you)", so you know they're great at working with their community.
If the main goal of Reason is to get a OCaml that is easy to use for JS devs, they nailed it.
I'm a JavaScript developer and I think the new version is easier to grasp.
Also, the Reason peeps are really nice and some of them are on a team of a FB product and not on the "Reason team", which gives them more insight of the day-to-day JavaScript problems, so I don't think they just do their thing and don't want any complains.
As far as I know Reason compiles to OCaml and back again, so there is probably no big barrier in using stuff written in Reason with OCaml, if you like that language more.
I even read about a few devs who started with Reason and switched to OCaml later.
If you disagree with this change, you can say that without ascribing bad intentions to open source maintainers whose contributions you apparently don't want to use anyway.
No need to use the past tense. Reason 10 just came out 2 days ago and added some awesome new synths!
Perhaps a small tagline in addition to the one (or two) word article heading to indicate what the article is talking about may assist in future...
Yes, the original OCaml syntax looks quirky during the first two weeks. But it makes sense after that.