OvermindDL1 / bucklescript-tea

TEA for Bucklescript

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ReasonML Syntax?

canadaduane opened this issue · comments

I know you (@OvermindDL1) really dislike the new ReasonML syntax. However, I'd like to make a case for embracing it.

I'm at a coding hackaway with about 25 software engineers right now. We're all building side projects and chatting and generally having a good time. So far, I've heard 3 separate people talk about Reason. I've heard 0 talk about OCaml.

There is a significant need that Reason/Bucklescript is filling in the web development community that I sense has a great deal of momentum gathering behind it. The Elm Architecture (TEA) is a great way to build web front-end code; however, Elm is not pragmatic and software engineers in my circle have mostly relegated it to a toy project. Reason, on the other hand, has great potential, and has a lot of "market fit" to use a business term.

I see a lot of people looking for TEA in Reason, but I see TEA in OCaml as "yet another friction point" in the journey of a javascript developer seeking to harness all of the goodness that the Reason+BuckleScript combo has made available.

What do you say to switching the default examples and docs to Reason? If we need to petition for changes to ReasonML, are there any specific syntax choices that would help make bucklescript-tea more useable?

I know you (@OvermindDL1) really dislike the new ReasonML syntax. However, I'd like to make a case for embracing it.

I liked it at first in early versions, fixing up some OCaml oddities, but it went kind of crazy lately... Like a big thing is conceptually breaking partial application stuff... (among many many other things that bug my about it's syntax choices)

So far, I've heard 3 separate people talk about Reason. I've heard 0 talk about OCaml.

That's common. OCaml's been one of those quiet powerful languages, like Erlang, where ReasonML is a big-company language (Facebook). Though, to be honest, I don't hold much stock in big-company languages being good (go/java/.net)... ^.^;

There is a significant need that Reason/Bucklescript is filling in the web development community that I sense has a great deal of momentum gathering behind it. The Elm Architecture (TEA) is a great way to build web front-end code; however, Elm is not pragmatic and software engineers in my circle have mostly relegated it to a toy project. Reason, on the other hand, has great potential, and has a lot of "market fit" to use a business term.

The whole post seems to keep implying that Reason doesn't just go down to OCaml though, it is not so much a new language as it is essentially just the old OCaml preprocessor system to have a new syntax on OCaml (which was so entirely common in the OCaml world that Caml4P used to be included with the base installation). You can mix and match ReasonML/OCaml/Caml4p/others all you want.

I see a lot of people looking for TEA in Reason, but I see TEA in OCaml as "yet another friction point" in the journey of a javascript developer seeking to harness all of the goodness that the Reason+BuckleScript combo has made available.

This library is entirely useable from Reason, there is no reason it should not be though. And if there are ways to make it easier to use then I'd probably do those if they do not sacrifice efficiency and so forth.

What do you say to switching the default examples and docs to Reason?

Well there aren't really any docs yet (other than the Elm docs), but that is planned... ^.^;

In the docs I was planning for one of those switch tabs to switch between OCaml and Reason anyway, so that was already on the roadmap (I think there is even a javscript library that can do that in-browser too, so that would make it way simple).

The examples could easily be done in both languages as well, but it is trivial enough to run OCaml code through refmt to get ReasonML code anyway that I just haven't put in any time in to it yet. (PR's always welcome!).

I would prefer the base source of this library to remain in OCaml though as it is the most compatible regardless (as everything lowers down to it). But examples could easily be in a variety of formats. Even a simple script that just runs refmt over the examples to put out *.re copies of them when I release is fine too.

If we need to petition for changes to ReasonML, are there any specific syntax choices that would help make bucklescript-tea more useable?

Hmm it already seems useable as it so, ReasonML is just OCaml with different syntax so I don't know what could be done to help/hurt anything. I do know of a couple that use this library in ReasonML without any complaints to me as of yet...

I want to make sure I'm on the same page, so if you'll allow me, let me write down some of my assumptions and you can correct any inaccuracies:

  • with regard to users of the ocaml AST, adoption of reason syntax is outpacing traditional ocaml syntax (esp. where javascript is the compile target)
  • growing the size of the bucklescript-tea user community is an important goal
  • it's ideal for newcomers to this project to:
    • get productive as fast as possible, and
    • be able to contribute to the codebase easily

I strongly support having the API docs and examples available in Reason syntax, as long as that can be done easily and automatically (e.g., with refmt or reason-tools). That would be a great step towards making adoption easier without reworking the whole project.

However, I feel rather differently about the library itself. As a once-contributor with a small bugfix, I realize I don't have too much to say about the current state of the project, but I'd like to advocate for the primary development of the library to be done in the OCaml syntax, unless there is some way to easily keep the two dialect versions in sync? (unfamiliar with the tooling story here).

Like @OvermindDL1, I find the new function application syntax wildly inconsistent with the semantics of the language (vis-à-vis currying, partial application, etc.), even though I liked that they cleaned up some of the warts of the OCaml syntax, e.g.:

But I think it is more important that the dialect chosen should reflect the preferences and mental model of the people writing the library, given that we have an easy, automated way for users of the library to understand the interface the library offers in the dialect they prefer.

Just as an additional useless data point. As a newcomer to pretty much everything special about this project (Elm, Ocaml and Reason), following any of the two current TEA tutorials was impossible for me so I'm gonna give Reason-React a try instead.

It's not just that the code is in Ocaml, even type signatures in the text of the Chess tutorial (otherwise excellent) are Ocaml-y. Don't get me wrong Reason-React is not all that much better. The website doesn't even scroll in my web browser :) But... I've used React at least.

I strongly support having the API docs and examples available in Reason syntax, as long as that can be done easily and automatically (e.g., with refmt or reason-tools). That would be a great step towards making adoption easier without reworking the whole project.

Yep, this was always a goal to have code examples in documentation available in both syntax's, and yep it is quite easily and automatically done with refmt. :-)

However, I feel rather differently about the library itself. As a once-contributor with a small bugfix, I realize I don't have too much to say about the current state of the project, but I'd like to advocate for the primary development of the library to be done in the OCaml syntax, unless there is some way to easily keep the two dialect versions in sync? (unfamiliar with the tooling story here).

Someone could always convert it reasonml via refmt, make changes, then using refmt convert it back to OCaml and that would work, although it would format the code differently (that might not be a bad idea actually, using refmt as a formatter, that might be worth adding in, hmm...).

Like @OvermindDL1, I find the new function application syntax wildly inconsistent with the semantics of the language (vis-à-vis currying, partial application, etc.)

Honestly I'd be quite perfectly fine if OCaml didn't have currying as long as it still had partial application, but currying is part of the first class function setup (functional programming of course!) so cannot really get rid of that. Using tuples as a full argument to a function (ala SML) would be more efficient and easier to optimize, but the OCaml compiler already uncurries way efficiently as it is (and if you need fine control you can just let something in to uncurry that call manually).

if-let-semicolon precedence

I'm one of those that are highly against semicolons personally, the semicolon/sequence operator is a design flaw in my opinion, they hide the return handling of an expression, which if someone really wants to do then they should do it via the explicit and self-documenting way of let () = ... in ... or so, yes it's longer, yes that is the point, you want to minimize ignored returns from expressions and make them blindingly obvious that they are there and what the type is (never use _ if possible, I don't always hold to this though but I really should, wish the language enforced it).

Consequently this change doesn't affect me. ^.^;

tuple syntax

Eh I'm torn on this honestly... The comma/tuple operator builds tuples, parenthesis are not part of their syntax and although I often use them they are not always convenient to use though. Honestly I wish they were just kind of like another normal operator that we could override though that would require GADT's or so forth, which didn't exist originally.

As for them requiring parenthesis, not big on that. I do like that it unified the type and declaration syntax's though. :-)

confusion of tuples and multiple-argument constructors

No such confusion in OCaml. f 1 2 3 is a function that takes an int that returns a function that takes an int that returns a function that takes an int that returns something. f(1, 2, 3) is a function that takes a tuple of 3 integers. It's very nice and clear and you can even mix them fine like f(1)(2)(3) is the first format, just with parenthesis added. It is very clear unlike ReasonML. Like if you want to do the curry form in ReasonML you do f(1, 2, 3), but that makes it look like you are doing a single function call, when you are NOT, the syntax is breaking an invariant. And what if you are doing a tuple call (SML-style calls instead of OCaml-style calls, which do exist in some OCaml libraries)? I'm not actually sure, maybe you have to do some horrid thing like f((1, 2, 3)) or something like that... This is one of the bad/stupid things they changed for a variety of reasons (the biggest of which is hiding that currying is happening, which you should be very aware is happening in case you have some hidden cost otherwise).

extent of match

Eh, I'm in the habit of doing begin match ... with ... end, and also their proposed OCaml code when run through ocp-indent would make it obvious that their scoping is a bit different than what they expected, so that is just a malicious example (ReasonML seems to have a couple of malicious examples, and this is actually one of the things that really bugs me about ReasonML's ecosystem...).

I've used React at least.

Heh, I actually quite dislike a lot of React, I think it is poorly designed in a few ways (which I can go into detail about if curious). Vue.js is a quite a bit better designed, though honestly I'm for more small webcomponent things of the webcomponent spec (if it would ever finish into browsers) that replicates information around quite efficiently while being significantly easier to reason about. I intend to replicate that style with a TeaComponent module set in time as I find it far easier to combine smaller re-useable Tea components rather than being forced to make monolithic ones.

But still, if someone knows a base set of language features, regardless of syntax or language (I started on assembly, so if you want to talk about lack of syntax ;-) ), then they can pick up essentially any other language with similar features with ease once they know those features exist, so the syntax argument between ocaml/reasonml is fluff anyway. OCaml is chosen here for ease of importing into any OCaml ecosystem, whether that is ReasonML, straight BuckleScript, native compilation, or compilation to something somewhere else (most of the non-bucklescript'y code would even work perfectly in F# for example, I'm still intent on stripping out the bucklescript special declarations sometime and putting them into self-contained modules for ease of compatability elsewhere). Compatibility between these systems is extremely important to me. :-)

It really does sadden me that BuckleScript doesn't follow the OCaml ecosystem terribly well, such as not working with standard PPX's, including another build system (fantastic though it must be, I really quite like ninja in my C++ work), etc... There is something to be said for standards. I could understand it adding 'more', but it should always completely and entirely work in every way back at the base ocaml ecosystem, if slower. ^.^;

@OvermindDL1 I'm curious if you read my assumptions, and whether there's any correspondence?

Someone could always convert it reasonml via refmt, make changes, then using refmt convert it back to OCaml and that would work, although it would format the code differently (that might not be a bad idea actually, using refmt as a formatter, that might be worth adding in, hmm...).

I think this might be a fun and profitable idea. Maybe a git hook that has a master-ocaml and master-reason branch, and whenever a commit is made to one, the inverse syntax is committed to the other?

Maybe a git hook that has a master-ocaml and master-reason branch, and whenever a commit is made to one, the inverse syntax is committed to the other?

That would be entirely doable yeah, hmm... Interesting idea. ^.^

Although probably just duplicating it to reasonml in another directory might work too..

I'm curious if you read my assumptions, and whether there's any correspondence?

Eh, to be honest I don't really care much about the horrifying javascript ecosystem nor about how languages grow (the horrors of things like javascript and go are great examples of why not to care), I prefer languages and syntaxes that I find myself to be most productive in for a given task (productive not just in immediate programming time but also in reducing my maintenance costs, which for a language like javascript is beyond excessive, though a language like OCaml is not). This library was initially made just to quickly/easily port an Elm application I had at work to OCaml, it's been growing beyond that though and I'm glad that others find use in it (plus it was a fun little project to spend some time on optimization the DOM access thereof to see how fast I could get views to work).

For a proper library set I really want to rewrite a good chunk of this, I learned some DOM patterns that could get it even faster and got a few ideas that would make it better to use if I don't mind breaking the Elm API, which I'm planning in TeaEx whenever I get it started (still way busy at work and I need money, so real life work takes precedence...). :-)

As an aside, I cannot wait until OCaml has a great webassembly backend. Though I've even made a Tea-like library in C++ in my experiment repo and played with one I found for Rust, but I still prefer OCaml-the-language overall so I'm waiting for it to get ported. My tea libraries will definitely work on native, webassembly, and bucklescript for as far as I can though. :-)

I'm one of those that are highly against semicolons personally, the semicolon/sequence operator is a design flaw in my opinion, they hide the return handling of an expression,

Somewhat O/T, but with the right compiler flags (warnings 5 and 10, I believe), which you most likely should be using anyway/are default(?), the compiler will reject any cases where you have a non-unit expression on the LHS of a sequence operator. It makes writing imperative code a lot cleaner, but that's just my opinion---I find let () = ... in too clunky.

which you most likely should be using anyway/are default(?), the compiler will reject any cases where you have a non-unit expression on the LHS of a sequence operator.

It might now, but it certainly didn't used to. ^.^;

It makes writing imperative code a lot cleaner, but that's just my opinion---I find let () = ... in too clunky.

Imperative code usually says to me Thar be dragons in this here codes!, so I want it as obvious as possible regardless. ^.^

Plus it helps to encourage better code to return information instead of mutating information. :-)

@canadaduane did some absolutely awesome work in #88, it is now merged and this issue is resolved as both OCaml and ReasonML code is available, works, and auto-converts. :-)