ReasonML/BuckleScript vs PureScript JS Interop

Fair enough. I guess it’s a matter of taste and I’ll defer to yours in terms of OCaml. I think it’s much nicer to be able to say Some_type.store .... Add to that that each call point would either have to defer to a specific encoding function if it did anything interesting anyway and you might as well have stuffed it into an interface. I don’t think it’s only the serialization that’s the point there, but rather that you have one place to change and set the rules in. Likewise, you have an obvious place to look for implementations in, as it will be obvious which types are trying to implement the interface (greppable, etc.).

Originally this was only about the FFI, yes, so that’s what I first highlighted; FFI functions + where they were used. I didn’t care to rewrite the OCaml code because I haven’t installed OPAM yet since I nuked my drive.

I said from the get-go that I’d rather have more code that uses less oddities, hence the difference in size between the FFI functions in PureScript + their companion interface that are curried. You can implement the actual FFI code being run as curried functions but it’s not encouraged; hence the double-up. And yes, as I’ve said here I’m now well aware that you can choose not to use these oddities and now I feel like I could’ve saved easily a couple of hours of total debugging time (I would say maybe I would’ve had more hair but I don’t think BuckleScript FFI decorators are quite bad enough to make me bald; I think I started balding because of too much C++).

As for the usage of LocalStorage, we’ve never used it for anything sensitive or for data that the client can’t have. It’s so far been used only for caching and it’s unlikely to change as we’re probably replacing the OCaml apps in the future.

Yes, this was a mistake on my part in trying to give more context and battling the obvious criticism of "You’re not showing all the code. So I decided that I’ll just show more PureScript code to get rid of that suspicion. They do different things, they’re from different times and one is an actual library and not just internal code.

With the exception of the JSOO stuff I’m well aware of these things. I used Reason as a way to sell it to my PM and then went with the obviously better syntax for a functional language. You should remember how many times I’ve criticized their choice to go full JS with the syntax, as I’m quite sure we both think Reason isn’t a useful thing except their community nowadays and we’ve essentially echoed eachothers’ sentiments on those points in every thread ever made about it here.

For something like yojson (basically the defacto standard for json parsing in OCaml, I’m not even aware of any other libraries it is so universal) it creates specific names, so for a given type like MyThing.t it would generate a MyThing.t_of_yojson and MyThing.t_to_yojson after adding [@@deriving yojson] to your type (which of course you can refine up or put indirectly on a remote type or whatever), so making something like that conversion module specialized for yojson as a JSON storage format in the strings would be significantly simplified (and in general that’s what I do, just something LocalStorage.set_item "thekey" (MyThing.t_to_yojson blah), and it’s both clear in what it is doing and how it is doing it while being short and easy to read, and if I need to do something other than json (like encrypting or encoding it somehow or whatever) then that’s trivial to do as well. If I really use something often enough I can just make a wrapper function for it (just a single line). Functors and First Class Modules have great uses, but this doesn’t really seem like one of them though? In addition it is still all easily greppable. :slight_smile:

If you are ever curious you should try out the effects-branch via opam and give them a try, it’s so fun to experiment, OCaml’s new effects system is the nicest of any language I’ve used yet. ^.^

Yeah all the attributes BS adds is way WAY too much noise. I use like 4 of them total I think and even that is generally not necessary at all. At the beginning BS was… not as noisy, it really only had those like 4 attributes because those were of the greatest use, but nowadays it has already pushed me back to JSOO for my newer stuff. >.>

Yeah it’s not useful for anything but a cache, way too many apps like to do things like store credentials in them though… >.>

No biggie, it was just an assumption on my part, and you know what they say when one assumes… ^.^

I never understood why ReasonML came about honestly… Facebook uses OCaml heavily internally so they already know it, and it’s syntax isn’t hard to pick up by any stretch (even more obvious since ReasonML is just a reskinning of it with adding braces and such weird useless things). Now preprocessors like caml4p/caml5p have great uses, nice syntax macro systems and all, but ReasonML just gives you nothing… Even the HTML templating syntax is a PPX that works on OCaml too.

1 Like

Well, we don’t point out that you can wrap everything and use just a couple of annotations because BuckleScript’s whole philosophy and direction has been to produce lean and mean output JS, fast, with as few extra wrappers as possible. So we pay that tradeoff pretty happily because we know it’s a one-time cost for each binding, after which everyone benefits from that lean code output. If that’s not your philosophy then fair enough, there are other techniques (or even languages) that you can obviously use.

ReasonML is about removing obstacles from the path of a wide variety of developers, mostly JS developers. And honestly, syntax is an obstacle. People keep saying this over and over again. If you need proof, think about what programming language’s forum you’re in right now and why it chose the syntax it did :wink:

1 Like

Hence why I kept saying above that a library should be used where they are already written. ^.^

Many of my external examples above with OCaml were of externals in general, including native code (not just most but near all of my OCaml is still compiled to native code). ^.^

I don’t see ReasonML as that though, it adds noise to the syntax that is otherwise clean.

And my own opinion of Elixir’s syntax is well known, I love the ecosystem (honestly the main reason it drew me in was the ecosystem, it’s so incredibly important how a good build and packaging distribution system is) and macro capabilities and so forth, but I extremely dislike the syntax, lack of spec (which has caused me unending problems and annoyances), and it’s extreme verbosity that hides so much of the actual work in the code being done… ^.^:

The thing about Elixir is the ecosystem, not the syntax by any stretch, rather it is the ecosystem in spite of the syntax. Anyone can pick up a language if the syntax is remotely usable, the thing is what power the language itself gives.

1 Like

Yeah, I see your point. I don’t personally think the cost of the functor is very high in terms of usage, etc., but your mileage may vary, I suppose, and I do see your point about this version being about the same with less groundwork.

It’s so odd because generally speaking the entire community around BuckleScript and Reason seems very concerned about having things that are easy to use, etc., but this pile of decorators somehow just grew and grew?

I actually thought it was pretty reasonable (badum-tish) at first. They wanted to standardize lambdas which I thought seemed like a nice idea. Then suddenly I had been away for a couple of months and they just made everything JS.

Precisely this; there’s so much superfluous stuff in the way, it’s not conducive to writing in. Who ever looked at an ML and thought “This needs more commas, parens and braces that aren’t useful for delimiting anything”?

Fair enough. I think it’s nice to have choices, but maybe the choices need to be spelled out more?

Is it, though? I can see a situation where bindings change and suddenly you’re (as in the general you) not sure whether or not the decorator you use is applicable anymore. Some of them are apparently optional or have become optional, etc… There are many rules baked into those and only in a pretty static world could they be considered a one-time cost. FFI bindings aren’t usually one-time costs in any language, so using a bit more code to make them easier to change seems like a pretty decent trade-off to me.

I think the issue was that it wasn’t obvious that I could use them? :smiley:

But fair enough, maybe this is a reflection of me more than it is anything else. I try to delve into communities and their practices very deep to get a picture of what people are doing, though, so I can’t honestly say that I think a nicer FFI alternative was advertised at all when I was engaged in Reason/OCaml with BuckleScript.

To be clear, are you asserting that adding tokens even though they don’t actually do anything useful (commas, parens, etc.) apart from adding familiarity, is a good thing? Wouldn’t it make more sense in this particular case to try to educate people on the OCaml syntax or at the very least try to make some things uniform but not add what amounts to only obstructions?

To also clarify, what’s the reason for the Elixir syntax as you see it? I think there are a few ways one can see it and I suppose they depend on perspective, but I don’t see how it’s objectively better than many other choices that could’ve been made. If the idea is that it was for familiarity for Ruby people and familiarity is a design goal in itself, then ok.

Elixir added other things, though, it’s not just a skin on top of Erlang. Having macros alone is good enough and if you’re doing macros, why not also change the syntax anyway, to make that easier?

Purescript doesn’t define a way to call methods on objects or use the new keyword so in order to use them in FFI you would need to define a helper function.

2 Likes

It’s more than just that, though. Anything you need a binding to that isn’t exported elsewhere in a PS file will have to be exported from a JS file named the same as the module you’re importing it in (the compiler checks both for the file and that the imported functions are defined, plus it checks for imports that aren’t used in PS but defined in the FFI file, so it’s not as rambo cowboy as it may seem):

exports.logUnsafe = console.log;
exports.window = window;

If you want to import it straight into Effect it’ll also have to be curried (for any parameters it takes) as well as return a thunk that should be executed when it’s to be run. It’s overall much better to not bother with that and just implement it with passed constructors, etc., so that you don’t put your complexity in the JS module. If they could somehow make the “I’m modelling Effect in JS” not a thing I’d be 100% for it, even though it increases the line count for the import.

Sure, maybe they do. We haven’t focused on that though because, like I said, I don’t believe that’s the philosophy of the community overall. There’s a lot of effort to get accurate, safe (as possible), lean bindings so that everyone can benefit. Writing wrappers for everything seems to defeat the point, imho.

Yes, this is always possible, but managing change is part of the job and we have tools (source control, semantic versioning) to help with that. Sometimes bindings become out of date, it happens. But at the very minimum we can guarantee that they don’t lose their type safety.

Well, I am taking a utilitarian approach here, even if something doesn’t feel like the best option to you or me it’s still worthwhile if it achieves a desirable outcome. Obviously I am talking about certain technical choices which don’t adversely affect the semantics or safety of OCaml here, I’m not in general advocating for a Thanos finger snap :wink:

Yes, that seemed to be the outcome José was going for, in my opinion. Well, since he used to be a Ruby on Rails core dev, it’s not a strange opinion, I think.

1 Like

This feels like a cop-out. There is a variable degree of issues you can have with FFI depending on how it’s designed. Other solutions have source control and all of those other things but what they don’t have is a complex append-only DSL. I’m sorry for pushing on this but it really doesn’t seem to hit home that maybe more thought should’ve been put into this aspect. And yes, I’m well aware that maybe this doesn’t seem like an issue in the community but if you talk to people in the Elm community they also don’t see any issues with Elm.

I think a utilitarian approach is as good as any other, but we don’t really know what Facebook could’ve done with just promoting and working on OCaml. The desirable outcome can’t be compared to “the other way” because you can’t simultaneously do both. It feels to me a bit like embrace, extend, extinguish, to be honest, except Facebook never tried to be open about being part of the bigger community, they just created a satellite one and built that community instead.

I would hope that’s a simplistic interpretation of that choice, to be honest. At the very least my interpretation is that some of the syntax choices at least lead to easier structure for macros, plus easy support for things like keyword arguments, etc…

Lol, that describes BS pretty well though, it just kept growing more and more parts not in the OCaml standard… ^.^;

It didn’t have some bad aspects at the start yeah, but then it also started a whole thing of “Let’s change everything!”.

Lol, precisely! :laughing:

It is a common thing for people to push the styles they’ve made though, I think the issue is that the community is never pointed to more traditional OCaml docs and tutorials, so they never learn the usual ways of doing things.

Eh, thankfully the HTML5 sub-specs are pretty well set, backwards compat is pretty important there (like 99% of the time) so libraries for the things work pretty well.

Or at least make them optional. ReasonML started out with its new things being optional, they aren’t anymore (and the few that are the formatter strips) thus making it more difficult to learn the base language… :frowning:

Elixir is so much on top of erlang! It replaced the old parse_transform’s with Macro’s, which are sooo close to lisp’y macro’s that you can kind of squint and pretend it is much of the time, plus the tooling is just absolutely top-notch!! ^.^

I do actually like the erlang syntax a lot more than elixir’s, but even its syntax I’m not really a fan of (it is simple and easy to read and use, but not very extensible… however it is very nice to transpile ‘to’ ^.^).

Yeah, that was my point, it doesn’t really have an FFI system, hence why you have to touch things like javascript in odd binding ways (you have to flex the javascript to fit purescript rather than the other way around).

I was thinking more along the lines of binding to JS libraries out there. Thinking in the same language as you do otherwise when you’re dealing with the FFI is simpler to me, when I need to adapt to and modify requirements.

In one of its forms, yes, when you’re not wrapping in the way I had in the FFI files. Fundamentally you have to create the bridge between what you’re using and PS, even if it’s literally just exports.unsafeLog = console.log. It has to exist. For the most part you shouldn’t need to write your JS oddly except when you need to return PureScript things that don’t actually exist in JS, like Maybe et al.

You can of course choose to just return the values that JS gives you and there’s stuff that handles the conversion of null to Maybe, etc., but you could never extend that to your own constructors anyway, so why not just go for a uniform way of passing your constructors to be used by the JS code if you need to? It’s predictable and uniform, it does exactly what you think it should.

I was suspicious of having to write JS at first but I prefer it now and I prefer the one that lets PureScript pass as much as possible. A constructor isn’t more costly if it’s passed through your FFI than it would be in your language unless you have some odd FFI barriers, but PureScript very intentionally doesn’t. Effect models thunks that are executed by JavaScript, so there’s no difference in speed to be had from trying to do more things in PS with the values returned by the JS side.

Actually I’m not sure what it is you’re pushing about. BuckleScript has a set of PPX extensions i.e. annotations which help with binding to JS constructs. You don’t need to use all of them, you can use a small subset of them quite successfully as has already been pointed out. If you use the more specialized ones you get leaner, lower-cost bindings with an equivalent level of type safety.

The annotation set is limited and has grown over time but is pretty stable by now because BS’s feature set has stabilized. I find it hard to take seriously the claim that ‘append-only DSL’ is a problem. If you want to preserve backwards-compatibility, you need to be append-only.

The truth is BS has vastly simplified bindings with one simple genius move: modelling potentially-undefined values as option types. So some of the annotations you found difficult with your original example would not even be used nowadays. This doesn’t make them wrong or unsafe in older bindings though, like for example TypeScript’s change in how it models undefined types did. It just makes them slightly more verbose than they need to be.

Sure, but by the same token, you can’t really say they made the wrong choice here. In fact it would be very difficult to make that claim after seeing so much interest in ReasonML and a lot of it generated by the familiar syntax.

Facebook is not really ‘backing’ ReasonML in the same way they’re backing something like React or GraphQL. It’s not centrally coordinated. There are a few people there who work on it, and are trying to advocate for it. The fact is that the tooling that Facebook created is fully backwards-compatible with the larger OCaml community. The only really distinct part is BuckleScript itself, which is a separate compiler, and also not originally a Facebook project.

If José had wanted easier macro support he would have gone with a classic Lisp syntax. Instead he made a tradeoff.

Keyword arguments have been ‘idiomatic’ Ruby syntax for a long time thanks to hashes. Elixir copies the spirit of that syntax almost wholesale, it just adapts it to use the more Erlang-y association lists.

To each their own. This is by far the worst part of BuckleScript as I see it and it seems to me that only someone with a vested interest in ignoring it would think otherwise.

All things being equal, the simplest choice is likely to be the correct choice. It’s only under the assumption or with the proof that things are not equal and familiar syntax is a positive differentiator that you can actually say it made sense to use this new syntax. Because we can’t prove that, it’s de facto the worse choice.

As I understand it, we don’t have years of data on Facebook engaging positively with and making marketing pages for OCaml to point to and say “See, people just don’t want ML syntax”. To say that engagement in Reason is there because of the syntax seems like a stretch. If they had marketed BuckleScript as a way to write OCaml for safer JavaScript output the same way they have with Reason it’s unlikely that there would be a difference. This idea that people want familiar syntax above everything else seems silly to me, especially when that familiar syntax is actually getting in the way.

This is kind of pointless information. They have a marketing page for Reason specifically, they have people talking at conferences about Reason specifically, etc… If anything, a small amount of resources mean you should use them more wisely, which maintaining the illusion of a separate language isn’t.

This is a neat one-liner, but it ignores the vast area in-between these two points. It’s true that a language with macros is best done with Lisp syntax, but it’s also at this point empirically true that Lisp syntax is a negative differentiator to adoption. Comparing ML syntax to Lisp syntax in terms of how much it rubs people the wrong way, you’d have to be either lying to yourself or have suffered some extreme indoctrination to not see that Lisp syntax is a bigger blocker for people picking up the language than ML syntax is.

In fact, I can probably count on one hand the amount of times I’ve seen anyone argue against OCaml because of syntax in discussions, whereas the syntax of Lisps comes up almost immediately. Sometimes in asserting “It’s bad”, but most of the time it’s just “Yeah, I didn’t want to start with it because the syntax was so weird”.

The only people I’ve ever seen comment on ML syntax somehow being worse are Reason users who’ve heard it time and time again from other Reason users, because it’s a meme in that community. The vast majority of those people had never even used OCaml before, so it’s not as if they’re a data point for Reason’s syntax somehow being better. It’s objectively true, though, that Reason’s syntax has several things in it that are pointless ceremony and that it’s not as good for writing ML programs.

You’re kind of missing the point. That particular feature itself made sense as a syntax change also independently of Ruby syntax, since there was already a precedent set with proplists in Erlang. You seem to be saying all this was just an accident and all Valim wanted was to have Ruby syntax. I think there was a much bigger basis for changing the syntax and given history I think Ruby syntax was an obvious candidate from a familiarity point of view, but there are several things in there that gel really well with macros and certain idioms.

Reason syntax has none of those qualities. None of the changes make sense with any added features because there are no added features and writing code with ML semantics is objectively worse with the syntax. Using Elixir’s syntax change over Erlang as a precedent for Reason’s syntax change over OCaml is at best ignorant and at worst plain disingenuous.

On the one hand, if this is the worst part of BuckleScript, then it must be doing pretty well; on the other hand, it makes it sound like I have some nefarious intentions for ignoring interop issues :slight_smile: the reality is that unless ReasonML/BS are wildly successful, I will likely make peanuts from it compared to the effort I put into writing my book.

Hold that thought…

Which they actually have–afaik Cheng Lou from FB set up the bucklescript.github.io site, wrote most of the docs, and put in double the normal amount of effort to make sure people could access the docs in both syntaxes.

It may seem silly, but syntax is the door into the language. If people won’t even walk through the door, how can they get into the language?

So syntax can matter for people to prefer languages or not? Just not your preferred ML syntax?

That’s a neat one-liner but I don’t think you dismiss it so easily. The fact that Reason users prefer Reason syntax is because of selection bias, but this means that they selected themselves into the Reason community because they prefer the syntax. In other words, these are people who would have never gotten into the OCaml community, but they did through Reason.

Let’s look at some of the changes (which were btw designed by the author of Merlin, so not exactly a JavaScripter deciding that OCaml needed a JS facelift), and look at the advantages objectively:

  • Function application syntax makes all applied arguments unambiguous and reduces the number of required parens when you pass multiple expressions in as arguments. E.g., foo (bar ...) (baz ...) vs foo(bar ..., baz ...).
  • Curly-brace scoping gets rid of all scope ambiguity e.g. dangling else’s, ambiguity about what semi-colon means in any context
  • Syntax supports single-line (//) comments
  • Anything that’s parameterized (function, data constructor, or type constructor) has a uniform syntax instead of three different syntaxes to learn
  • Syntax for modules and module types is actually unified and less verbose ({...} vs struct ... end and sig ... end)
  • I’m not even going to detail other syntax conveniences like JS object literals and JSX

I don’t see why the OCaml/Reason to Erlang/Elixir comparison has to pass your particular narrow test; that seems like overthinking something that’s really very simple: use a familiar syntax and take advantage of that familiarity to design a language attractive to outsiders.

Big reason why I don’t like using a lot of those libraries, lol. ^.^

Which in javascript I’d say is either null | value, unless null is a valid value then use undefined, unless that is also a valid value in which case wrap it in an array of 0 or 1 elements depending. ^.^

I think BS does the the undefined as None and anything else as Some if I recall right… JSOO does… byte-level stuff (low level compiler remember)… ^.^;

One big reason that I’m not wanting JS in OCaml (and why I really don’t like BS going this way of attributes and such) is that I intend to jump to wasm as quick as is feasibly implemented by 99% of browsers, and having javascript makes that…rewritey. ^.^;

OCaml only has experimental WASM backends so far, honestly at this point I’m leaning more to Rust, it has such a fantastic wasm ecosystem at this point! :slight_smile:

Too true there.

Yep, originally made and endorsed by Bloomberg, though then the author left back to china and it is now only supported by him and the community around it.

BS really should have gone the compiler plugin route instead of forking and dealing with keeping it updated. If he couldn’t do something as easily as he wanted then PR’s should be put in! :slight_smile:

Such an infrastructure would make writing a BEAM backend for OCaml even easier if he did. ^.^;

Wait… why would someone use a hash table to implement keyword arguments? That sounds horrendously inefficient. Even a linear list lookup (like keyword lists) are faster until ~10-40 elements and keyword arguments will almost never reach that size… o.O

Even Elixir’s maps use a list internally up until a given size, at which point it changes implementation (still not something you could call a hash storage as it is just a 'map’per is all from key to value via a few different implementations), as most maps on the beam tend to store few values so optimizing for that case is useful.

Exceptionally this. The quote/unquote “Familiar” syntax for me is C++, it’s what I lived and breathed for over 20 (near 30?!) Years. Just because I know it excessively well does not make it Good (because it really really isn’t) and I really don’t want newer languages to mimic it (Oy rust…). Look at how popular C/C++ still is, or look at how popular Java is, or look at how popular Perl was or PHP (somehow) still is? They are pretty universally known as having horrible syntaxes, but they are all huge successes in spite of their syntax’s, like Elixir, who’s syntax gets in the way pretty often but the nice points of it override it enough to ‘Deal with it’. ^.^

Eh, I’m not sure I’d say that. The base lisp syntax is exceptionally powerful and it was really taking over as ‘the’ language format until the old (joke) AI industry collapsed, which since it was so ‘known to be tied with’ the AI industry it fell with it. In addition with everything from macros to read-macros and all you can get any syntax you can think of and create in a Lisp language, you could implement Elixir’s syntax in a lisp without ‘too’ much work (would be easier if Elixir actually had a spec…). There is a reason it is generally considered the most effective programming language to program in. Should take a look at Racket, it’s a modern scheme and it shows it off very well.

Not hard to get an ML syntax on a Lisp either. ^.^

Remember that you aren’t really ‘supposed’ to program in the base lisp’y syntax, even the original implementation was building a language on it, the lisp syntax was just the middle AST format, it’s just that people ended up liking it a lot more overall so the language being built on top (bugger I can’t remember the name, started with an M I think?) just kind of fell to the wayside.

Too true, it’s syntax is wonderfully unambiguous, short, and clear.

Always be people that don’t program in it too I must note. ^.^

Contrast that to C/C++ and many if not most programmers of those languages will love to nitpick on the horrors of the language syntax. ^.^

I really really wish keyword lists in Elixir had the full proplist range!! I keep missing proplists so I end up encoding what they used to do with needless noise like enable_thing: true instead of just :enable_thing and value: {"blah", 42} instead of just {"blah", 42} (or "blah" => 42 I’d expect in Elixir’s syntax). Elixir maps and keyword lists have this weird and incompatible syntax overlap that makes them bugger-all confusing for newbies, I distinctly remember wondering what was broken in elixir when I could use "blah" => 42 as a key/val pair in a map but not as a key/val pair in a tuplelist when blah: 42 worked fine in both, they either need to use different syntaxes for all constructs or work with the same syntax in all constructs. To this day I still don’t know why ... => ... is not allowed in keyword lists as it seems the explicit pairing of _: _ too but generic… Like why can’t I do [value => 42] when value = :option_name, it makes no sense!! o.O

Honestly I even think that ReasonML requiring parenthesis on tuples and function calls is such a huge misdesign, and that was even how it started… ^.^;

OCaml could even get an elixir-like macro system, the ppx_stage library is an experiment that shows how it could be done, and if it were fully ‘fleshed out’ or even baked into the language as official constructs instead of attributes then it would be so fantastic!

I thought it used refmt to automatically generate the conversions from OCaml to ReasonML for the examples? Even my github library does the same, I have a src-ocaml and a src-reasonml (src-reason? whichever ^.^) and if one is edited then a git hook auto-converts it to the other upon commit. It’s not hard at all. :slight_smile:

refmt is pretty well made, the language I may think have a lot of syntactical issues, but the tooling is pretty solid. Now if only it converting back to ocaml from reasonml didn’t make it look like the spacing and readability was destroyed. ^.^;

Those people make no sense to me… Even I try to learn at least 3 new languages a year (the more different and weird the better!) as it makes me a better programmer everywhere else… >.>

I’m of the opinion that putting expressions of any real size in a function call is hard on readability and should be lifted to a let ... in ... before it instead.

Those aren’t ambiguous though? And I’m quite against ; in OCaml as it hides the return value (if it’s unit then match it to unit via let () = ... so things don’t magically break if the type signature changes, if it is not unit then you should probably do something with it, even if just checking for some successful value).

Meh? (* ... *) is not exactly hard to write, especially when I just hit Ctrl+/ in my editor to wrap the line the cursor is on or wrap the entire selection.

The 3 syntaxes are all simple and unambiguous about what is being done, thus making it easy to read and comprehend what is actually happening and ‘what’ the code actually is.

True, this is one of the changes I’ve liked, though it needs some differentiator to tell the difference between sig and struct otherwise { is ambiguous without surrounding context (more for a human to read!).

JSX works in a PPX last I saw? And as for JS object literals? Huh? Since when can you use JS objects in native code (which syntax should be ambivalent toward the backend)? Or are you talking about some non-standard bucklescript extension that won’t work with JSOO or bytecode or native or etc…?

I don’t know if other contributors have done that but as far as I know there is no tooling in the website’s repo to auto-convert. Whatever I’ve contributed there I’ve just translated manually. I assume others have done the same.

‘Dangling else’ is a well-known problem in OCaml, see section titled ‘Motivation to close the constructions’ in The revised syntax

True but // is even easier :wink:

Well, this thread is primarily about BuckleScript, so that is what I am talking about :slight_smile: If you’re dealing with JS objects, then you have to accept that you’re not going to be able to port that particular code to native.

I’m not finding any reasonml on the current BS website from a quick look, it used to have a javascript plugin that ran refmt in the browser on demand, but not seeing that either, hmm. Might have been removed since then.

Those aren’t ambiguous (and things like ocp-indent makes it obvious what it is actually doing). Constructs like that from the example:

     match ... with
       case1 ->
         match ... with
           case11 -> ...
         | case12 -> ...
     | case2 -> ...

Is interpreted as:

     match ... with
       case1 ->
         match ... with
           case11 -> ...
         | case12 -> ...
         | case2 -> ...

Because that is what it actually is. OCaml is not a whitespace sensitive language and treating it like Python is of course doomed to fail. And OCaml has constructed for binding it, you can easily do:

     match ... with
     | case1 ->
         begin match ... with
         | case11 -> ...
         | case12 -> ...
         end
     | case2 -> ...

Or do it on all matches if you so wish:

     begin match ... with
     | case1 ->
         begin match ... with
         | case11 -> ...
         | case12 -> ...
         end
     | case2 -> ...
     end

Which is quite nicely readable in any case. Regardless in all cases it is unambiguous, each case head is a continuation of the most recent case head, there is no ambiguity. The above example only looks ambiguous because the person didn’t use whitespace in a logical manner (of which, again, ocp-indent can fix, doesn’t every OCaml IDE use ocp-indent built-in anyway?). You can make many patterns ‘look’ like something else by just changing the whitespace, it’s doable in Elixir too (and in fact that has happened to be a few times… >.>), but that doesn’t mean the code is ambiguous. Even in Elixir I’ve had deep case trees where I’ve had the indentation wrong and thought some heads belonged to a different case, and Elixir even has trailing end’s. This is purely a case of the writer of that code not keeping case heads together that are related and the lack of using tools that make it obvious, like ocp-indent that every OCaml IDE I’ve seen will use to do just that.

In addition the case’s are probably of different types (and if not the program is probably not well typed enough anyway) so it wouldn’t compile if it was binding to the wrong match than expected anyway.

On an aside, I wouldn’t be opposed to a trailing end in a match, it could even be optional and still unambiguous.

Not when reformating paragraphs of docs and now you have //'s interspersed in the docs instead of at the start of lines. :wink:

/me always prefers block comments, nestable block comments especially

Ah I thought you were talking about ReasonML and not Bucklescript? At least that’s what the rest of the paragraph that was in seemed to state? o.O

You had to use several paragraphs to explain what the nested match rules were :slight_smile: in ReasonML, it’s one sentence: switch expression scope is delimited by curly braces, that’s it. No need for a formatter, IDE support, etc.

Well this thread is titled ‘ReasonML/BuckleScript … interop’ so I’m talking about ReasonML syntax in the context of BuckleScript interop :slight_smile:

Syntax can matter, yes, (it shouldn’t, but let’s be realistic) when it’s sufficiently alien to people that they don’t want to start engaging at all. My point being that I’ve never heard anyone outside of the Reason community actually bring up the ML syntax as a negative differentiator. As you noted, people self-select into that community and if I had to guess I’d say they learn to dislike the OCaml syntax mostly because they hear about it a lot. This happens in every community; they start adopting values they’d never actually have otherwise, even if they don’t know why they adopt them. Like I said, it’s a meme at this point.

As for your point about how I make a difference between one language’s syntax and another… They have varying degrees of challenge to newcomers. Back to the point about Reason people being the only ones, etc., bla bla.

So we make the best case worse and the worst case the same by having less parens in the worst case but always forcing commas, right. I’m not seeing any wins here.

I’ll take your word for it.

Haha, what? This seems a bit of a reach.

One of the decent changes they started out with, yes.

Fair enough.

It’s not a particularly “narrow test”. It was an assertion that Elixir already were making changes on the actual language level and making changes to the syntax at that point to support neater versions of already existing idioms made sense. Reason has made no substantive changes to the language itself and so there is no syntax change that’ll actually support those decisions.

I’ve written Racket for about 6 years at this point, I’m well versed in it and I know all the upsides of S-expressions. I wouldn’t miss a second to tell people how fantastic it is if they were interested in it, but this doesn’t change the fact that it’s an empirically disliked syntax. The fact that people usually would assume that because I say this I must have no experience with Lisp is a testament to how people have a very hard being objective about these things. I don’t.

Was speaking of other things too, the rules in OCaml is that a head matches with the immediately prior head, super simple. :wink:

Likewise, I’ve often heard of ML syntax being talked of as one of the best, that was why I originally started looking at SML decades ago. o.O

+1

DIslike by whom though, you stated that you like it here?