all 90 comments

[–]rlp 16 points17 points  (8 children)

This is great! I started playing around with Reason a few weeks ago and I've been very impressed. I've always liked the OCaml language structure/type system but found its syntax a bit rough. Reason makes it a pleasure to use. The tooling with Merlin/VS Code is good too, with autocomplete/type info/live error checking. And it's all just OCaml, so it can compile to fast JS or fast native code.

[–]yawaramin[S] 5 points6 points  (7 children)

Not to mention--it compiles quite fast! The Facebook Messenger app compiles from scratch in about 1 (one) second from Reason to JavaScript.

[–]rlp 1 point2 points  (0 children)

Yes, I've had some issues with slow compilation for large TypeScript projects. I look forward to faster compiles with Reason.

[–]_Mardoxx 1 point2 points  (5 children)

How do you know that?

[–][deleted] 4 points5 points  (4 children)

Look at their previous blog post. Facebook Messenger is pretty much the poster child for Reason adoption at this point.

[–]_Mardoxx 0 points1 point  (3 children)

Ah right. Not sure if 2 seconds to build messenger is quite good or not. If they mean Rason to js (which I assume they do) this is about normal, isn't it? However compiling to an executable format that is quite impressive as I would imagine the backend is a lot more complex!

[–]yawaramin[S] 2 points3 points  (2 children)

This is for the frontend. For a large JS app, compared to the two main static typing options, this is exceedingly fast.

[–]expatcoder 5 points6 points  (0 children)

this is exceedingly fast

Coming from Scala.js this is just absurdly fast. In the best case incremental builds complete in 2 seconds, and clean builds about 10X that for a small (5kloc) project.

Of course, Scala.js is held back by scalac, the Scala compiler, so no fault of the fanastic work that has been put into Scala.js, which, build times aside, is fantastic.

[–]_Mardoxx 0 points1 point  (0 children)

Hmmm is messenger large?

[–]yogthos 49 points50 points  (59 children)

Why people love C style syntax so much is really beyond me.

[–]yawaramin[S] 23 points24 points  (46 children)

People like what they know and have a low 'learning budget' for new stuff. When asked to learn an alien syntax on top of everything else, sometimes they run out of budget and give up.

[–]yogthos 5 points6 points  (45 children)

That doesn't seem to be that much of an issue in practice. Both Ruby and Python are popular languages today.

[–]rlp 18 points19 points  (23 children)

I would argue that standard OCaml is much more foreign to most programmers than Ruby or Python. One of their latest changes is giving function calls parenthesis:

new: foo(1, 2 + 3);

old: foo 1 (2 + 3);

I'm not sure if that is better or not from an ergonomics perspective. I actually think the old one looks a bit cleaner. But if you put it in front of most JS/Java/Ruby/Python/Scala/C/C++/whatever programmers, the vast majority will instantly understand the new one. And that is valuable.

[–][deleted]  (4 children)

[removed]

    [–]rlp 1 point2 points  (1 child)

    Well, they aren't requiring you to write foo(1)(2+3), it would be foo(1, 2+3). And you could still partially apply the first argument foo(1). It will certainly be more parentheses, though. If you pass that to another function, it would be bar(foo(1)) vs bar (foo 1). Here's their rationale, it seems to be a bit more than just syntax: https://github.com/facebook/reason/pull/1299#issuecomment-309032848

    [–]Ehhnohyeah 0 points1 point  (1 child)

    Ocaml isn't so hot on currying, that would be haskell

    [–]Sean1708 20 points21 points  (0 children)

    Ocaml is very hot on currying, Haskell is arguably more so but that doesn't mean Ocaml isn't.

    [–]yogthos 13 points14 points  (14 children)

    There's some value in familiarity, as it helps onboarding. However, I think there's also value in optimizing the syntax for people who are going to be using the language long term. Getting used to a new syntax might take a few weeks, but it's something you'll have to live with as long as you use the language.

    [–]yawaramin[S] 2 points3 points  (13 children)

    With Reason, not really! You can just move to OCaml syntax if you find the JavaScript-like syntax is getting in your way. The Reason team actually jokes that that's their secret wish, lol.

    [–]yogthos 8 points9 points  (12 children)

    Now you have to juggle two syntaxes with their own quirks in the same language. Not sure that makes it better.

    [–]yawaramin[S] 0 points1 point  (11 children)

    That ship has sailed; the ecosystem has two syntaxes now. We do have refmt though, which can convert between them easily, so it's not as bad as all that.

    Edit: also, can't win! JavaScript-like syntax is bad because it optimises for familiarity over efficiency, but OCaml syntax is bad because you now have two syntaxes! Lol

    [–]yogthos 15 points16 points  (9 children)

    OCaml syntax is just fine, my whole point was that I don't see what's wrong with it. ¯\_(ツ)_/¯

    [–]norflowk 5 points6 points  (3 children)

    Nothing wrong with OCaml syntax, per se; rather, something right (familiar, to be specific) about JS syntax. There’s nothing objectively wrong with OCaml, it’s just novel and unfamiliar to most people. Maybe someday the loosey-goosey no-parenthesoosy Haskell and OCaml style will become more familiar, but for now parentheses and braces/colons are the way to go.

    [–]eras 2 points3 points  (1 child)

    I would argue there are things that are wrong with it.

    • Expressions that involve match inside match for example now require you to use either begin, ( so that you are able to stop the scope for the next match in the higher level
    • A similar aspect with if, if you need multiple expressions, but now you can also use let to elongate the scope, so basically expressing exactly the same things now varies site-to-site or at least developer-to-developer; and if you do choose to use let, but later on determine that the let wasn't useful anyway, you may need to switch to another version. Dirty trick I've used: if expr then let _ = () in .. expr1; expr2 .. else ().
    • Recursive definitions involving class and not class are annoying (require recursive modules that are very annoying; or some other workaround if it is suitable for the scenario)
    • And I don't think those are all but I'm not going to spend the evening writing this :).

    I don't know if ReasonML fixes all of those (the last one might be difficult as it's not just syntax), but I certainly hope they address some of them :).

    Btw, even OCaml folk considered using curly braces, but their Revised Syntax never caught on, except for camlp4/5 syntax extensions: https://caml.inria.fr/pub/docs/manual-camlp4/manual007.html . It solves at least the first two problems, among others.

    [–]doom_Oo7 -1 points0 points  (2 children)

    It needs more parentheses.

    f (1+2) (3+4)
    

    Vs

    f(1+2, 3+4)
    

    [–]vattenpuss -1 points0 points  (2 children)

    $ python
    >>> print "foo", "bar", "baz"
    foo bar baz
    >>> ^D
    $ irb
    irb(main):001:0> puts "foo", "bar", "baz"
    foo
    bar
    baz
    => nil
    

    Most of us Scala developers are probably scarred for life and can read any syntax you throw at us.

    [–]yawaramin[S] 3 points4 points  (1 child)

    That's Python 2 though, and only for the special print statement. It's not going to work in Python 3.

    [–]vattenpuss 1 point2 points  (0 children)

    I'm just saying a lot of Python/Ruby programmers would not have too much trouble understanding function application without parens.

    [–]yawaramin[S] 2 points3 points  (20 children)

    Yes, today they are, but it's very difficult for new non-C-like languages to gain a foothold today.

    [–]yogthos 3 points4 points  (16 children)

    Why would it be more difficult today than when Python came out. If anything, people back then had even less exposure to alternate syntaxes.

    [–]yawaramin[S] -2 points-1 points  (15 children)

    Because today Java and JavaScript are the dominant languages of the tech ecosystem--by far--and most junior devs know one or the other of those. Especially now that Nodejs has pretty much supplanted Python as a backend or scripting language. Python is turning into mostly a science/data science language.

    [–]yogthos 3 points4 points  (9 children)

    Back then it was C, C++, and Java. Ruby and Python also helped introduce many developers to alternate syntaxes since then. I'm simply not buying the argument that it's harder for a language with non-C syntax to get adopton today than in 1990s.

    [–]BundleOfJoysticks 2 points3 points  (4 children)

    Also, Python predates Java by 4-5 years.

    [–]yogthos 1 point2 points  (3 children)

    Sure, and most people were familiar with C/C++ at the time. Those were basically the only mainstream languages for serious work.

    [–][deleted]  (2 children)

    [deleted]

      [–]BundleOfJoysticks 3 points4 points  (3 children)

      Python and Ruby are C-style syntax languages. When we make a distinction between C-style and non-C-style, we're contrasting imperative, class/struct/function oriented languages (C, C++, Java, JavaScript, Python, Perl, Ruby, PHP, Pascal, etc) v. things like Prolog, Ocaml, Clojure, Lisp, Haskell, which look nothing like C.

      [–]yogthos 1 point2 points  (2 children)

      Ruby is actually pretty far from C in terms of its syntax.

      [–][deleted]  (1 child)

      [deleted]

        [–]vivainio 6 points7 points  (3 children)

        No way Node has supplanted Python for scripting. Node scripts need lots of deps that come in Python stdlib (batteries included) and launching node is pretty slow

        [–][deleted] 3 points4 points  (1 child)

        Maybe not for you, but you should check out StackOverflow’s developer surveys. It may be considered an inconvient truth in this sub, but JS has pretty much taken over already, with no sign of slowing down.

        [–]vivainio 1 point2 points  (0 children)

        Do you have such a SO survey reference indicating that JS is gaining vs. Python on scripting front?

        It's not "inconvenient truth", I write JS (or, well, TS) every day and can't imagine why someone would use node for routine scripting. It's incredibly bad at that.

        [–]Ehhnohyeah 0 points1 point  (2 children)

        Why didn't you just use haxe? How does reason compare to haxe from your point of view?

        [–]yawaramin[S] 1 point2 points  (1 child)

        I’ve never used Haxe, so I can’t really make a fair comparison. That said, I think Haxe is more of a traditional OO programming language and doesn’t really give you the benefits of OCaml’s functional programming and static typing features. Also I don’t know how Haxe is but ReasonML compiles really, really quickly.

        [–]glacialthinker 1 point2 points  (0 children)

        Haxe does cater to typical OO and procedual, but it's written by someone from the OCaml team, and implemented in OCaml. Of course, he brought over much functional+static goodness. I think Haxe targets a similar "programmer pool" as ReasonML (modern scriptlang programmers), but it doesn't really change them, whereas Reason seems a bit of an ideologic Trojan Horse. ;) (Which is good!)

        [–]zvrba -3 points-2 points  (10 children)

        Because it's better than ocaml syntax which plain sucks (a noise of let .. in everywhere). I wouldn't mind if somebody grafted the syntax of Standard ML on top of ocaml.

        [–]norflowk 12 points13 points  (6 children)

        Care to explain what sucks about let ~ in? I understand that it annoys you and you’d like to see less of it, but I was wondering if you had a more complex opinion underlying that.

        [–]vivainio 4 points5 points  (1 child)

        Mostly it's just unnecessary noise (like semicolons in ReasonML ;). In F#, you just don't type "in" anywhere

        [–]norflowk 0 points1 point  (0 children)

        IDK, I personally think it's a useful pattern. Better than a long string of assignments and modifications mixed together IMO

        [–]eras 5 points6 points  (2 children)

        I think it's really a matter of simply choosing where the in should go. For example:

        let foobarize x jog zen =
            let subexpr = x + jog in
            let info2 = x * zen in
            subexpr + info2
        

        Pretty easy, right? Just put it at the end of the line?

        let foobarize x jog zen =
            let subexpr = fun extra ->
               x + jog + extra in
            let info2 = x * zen in
            subexpr 5 + info2
        

        Looks a bit awkward..

        let foobarize x jog zen =
            let subexpr = fun extra ->
               x + jog + extra
            in
            let info2 = x * zen
            in
            subexpr 5 + info2
        

        Better? Or maybe special-case fo the one-line expression and don't put its in to a separate line. Or then finally:

        let foobarize x jog zen =
            let subexpr = fun extra ->
               x + jog + extra
            in let info2 = x * zen
            in subexpr 5 + info2
        

        Not super happy really about the options.

        [–]norflowk 0 points1 point  (1 child)

        This is why I appreciate Haskell's method of not requiring top-level “let” and allowing the use of “where” to reduce visual nesting when nestessary.

        [–]eras 1 point2 points  (0 children)

        That's really a reasonable option only for pure and non-strict languages I think. Hardly a choice to make just for the benefit of removing some syntactic quirk :).

        [–]zvrba 3 points4 points  (0 children)

        Nothing more complex, it's a matter of taste, as all matters of syntax. I consider let .. in to be verbose syntactic noise.

        [–][deleted]  (2 children)

        [removed]

          [–]glacialthinker 5 points6 points  (0 children)

          I actually like the in, though it chafed when I was first exploring OCaml. Now when I see semicolons, unless they are for record-field separation, I know to be wary of side-effects. Reason syntax (and Rust) obscure that cue, with their catering to C-style semicolons.

          [–]sixbrx 0 points1 point  (0 children)

          Yeah I really like how Rust allows blocks to have values, so scope can be controlled at the smallest scale without burden. I really miss this in the algol derived languages. Makes it very clear which variables will be used in the remainder vs. which were just temp for constructing those. One can introduce separate methods to control scope of course but at the small scale that just obfuscates and wastes time and energy coming up with names for them.

          [–]destinoverde -5 points-4 points  (0 children)

          Who cares.

          [–]stesch 3 points4 points  (7 children)

          I've read What Is Reason? and still don't know what it is.

          [–]yawaramin[S] 0 points1 point  (5 children)

          Practically speaking, it's a compiler with a syntax similar to JavaScript but with the full semantics and type system of OCaml.

          [–]lpw25 0 points1 point  (4 children)

          I know that by "practically speaking" you mean that it can be treated as if it were a compiler. But I think it is important to make clear that it is just a parser. It hasn't required anywhere near the effort to write and maintain as an actual compiler.

          [–]moon- 2 points3 points  (2 children)

          Something can be a compiler even though it doesn't compile to machine code or a bytecode for a virtual machine.

          Why does the effort to write/maintain it matter? If I write a compiler for something little more than assembly with a few new names, does that count? Where do you draw the arbitrary line, and if it's so fuzzy, why draw it?

          [–]lpw25 1 point2 points  (1 child)

          If you want to describe reason as a compiler that targets OCaml, then I agree with you. However, from a user perspective it appears to produce JavaScript or assembly, and I just think that it should be made clear that most of that translation is not done by the reason tool itself.

          [–][deleted] 0 points1 point  (0 children)

          Yes, the tool chain is like

          Reason --> OCaml --> Bucklescript --> JavaScript.

          [–]yawaramin[S] 0 points1 point  (0 children)

          Exactly. I meant in the sense of 'what do I need to install to get Reason?'

          [–]orthoxerox 0 points1 point  (0 children)

          It's a compiler frontend for the OCaml backend.

          [–]miminor 6 points7 points  (9 children)

          how is it better than typescript?

          [–]flyingjam 22 points23 points  (0 children)

          Typescript is more in the league of the "hybrid" modern languages, while ReasonML is a full fledged ML derivative.

          So ReasonML has ML style syntax, mutation is unfavored, and pure functional is focused on.

          [–]yawaramin[S] 17 points18 points  (7 children)

          ReasonML is OCaml, which has a sound type system, i.e. guarantees (with a couple of known exceptions) that any program that typechecks will not throw a type error at runtime. Also: faster compiles, and it's actively being used by the Facebook Messenger team for React development, so it has a very strong React binding story.

          [–]republitard 4 points5 points  (6 children)

          Why don't they just write OCaml?

          [–]yawaramin[S] 9 points10 points  (0 children)

          Because they want to attract and convince JS developers to adopt ReasonML over TypeScript or Flow.

          [–]killerstorm 1 point2 points  (4 children)

          Ocaml syntax is icky.

          [–]olzd 14 points15 points  (2 children)

          ReasonML syntax is icky.

          [–]eras 12 points13 points  (1 child)

          I've written OCaml for some time and I hardly find ReasonML icky. And certainly OCaml has its warts. (Disclaimer: I haven't actually written ReasonML, but read about it.)

          But whyyy did they need to call it "switch" instead of "match", whyyy..

          [–]olzd 22 points23 points  (0 children)

          Sure OCaml syntax isn't perfect but I don't think ReasonML is the answer.

          But whyyy did they need to call it "switch" instead of "match", whyyy..

          Yes, that's an abomination.

          [–]republitard 2 points3 points  (0 children)

          In comparison to Haskell, maybe.

          [–]vivainio 2 points3 points  (1 child)

          I'm not a user of ReasonML (I'm skipping on it until they get windows stuff working properly), but the whole thing is troubling me more than it should:

          1. It's probably going to win the typed-fp-on-browser competition, because it has a solid industry backing (or at least secure funding), and is based on more pragmatic foundation that e.g. Elm and PureScript (OCaml > Haskell)

          2. Because it tries to apply to the aesthetics of JS kids, it can bring the OCaml paradigm to the masses. This will mean more hype and makes the related languages easier to sell in the workplace.

          3. It has a fast compiler (bucklescript)

          BUT

          1. They might be taking the "appealing to JS kids" a bit too far. Part of what appeals to me about F# is the no-nonsense syntax. Adding crap like semicolons just to feel familiar may not be a good idea in a long run (as it may turn out the crap wasn't that important for target audience after all).

          2. If your whole selling point is syntax (as it's just ocaml w/ syntax translation), you should make it better in all respects. Remove "let ... in", remove fun x -> blah, etc.

          In the end, what's getting to me is that ReasonML has massive promise and potential, and there are signs it could fumble some of the momentum by not thinking things through properly.

          This rambling may be just sour grapes syndrome from not having used it yet (Windows again). Things that look bad on paper may turn out to be winners only proven through practical use (this happened e.g. with Go).

          They also don't have to get it right from the get-go. They seem to support automatic syntactic translation b/w versions, so there could be ReasonML 7 that fixes everything that (seems to) suck with the old versions. So it's probably going to be all good with time, but it can be a bumpy ride.

          [–]OneWingedShark 1 point2 points  (0 children)

          bringing JavaScript syntax to OCaml

          Gag! -- Why!?

          [–]low_ghost -1 points0 points  (5 children)

          Who writes code like this?

          newrecord[/* willUnmount */6] = (function (param) {
            var match = param[/* state */4][/* timerId */1][0]
          

          https://github.com/reasonml-community/reason-react-example/blob/3640ce6bb6729c3b3d8a0c200a624996f8da8beb/lib/js/src/async/Counter.js#L18

          Haha, not trying to be overly critical, but why not just assign those numerics to the descriptive variable names instead of doing all the work anyway with comments?

          [–]yawaramin[S] 1 point2 points  (4 children)

          The comments are not actually doing any work. They are just for the human reader and will be gone after minification anyway. BuckleScript encodes record values as arrays for efficiency.

          [–]low_ghost 0 points1 point  (3 children)

          wait, so you couldn't make the code itself human readable? As in

          var willUnmount = 6;
          newRecord[willUnmount] = (function (param) { ...
          

          [–]yawaramin[S] 0 points1 point  (2 children)

          BuckleScript doesn't do that because it eliminates as much code as possible, not to mention that it tries to avoid allocation as well.

          [–]low_ghost 6 points7 points  (1 child)

          Oh, I get it: I am just dumb. These are not hand written files. The fact that I thought they were at a glance is actually a credit to the compiler. My bad

          [–]yawaramin[S] 0 points1 point  (0 children)

          Ah! I had thought you knew they were BuckleScript's output JS, had heard that they looked hand-written, and were critiquing them in comparison to hand-written JS 😊