Callback hell was before the introduction of Promises. Promises tried to abstract away the callback mechanism and it made things a little clearer, but you still had the pyramid effect of successive Promises.
I still somewhat prefer the readability of promises vs. await. I like the expressiveness of a then/catch as functions as opposed to try/catch blocks, which I‘ve always disliked. But I agree that await is more suitable for more complex scenarios.
async/await is just a syntax sugar, most languages didn't have it until very recently when it became a trend or something. In OCAML it's just like any other monad you use the bind operator instead. No need for special keywords.
C# 5.0 introduced async/await in mid-2013 (late 2012 depending on how you count it), and F# had it before that in its version 2.0 (~2007). It's a pretty old "trend".
I was arguing that languages are following the "add async/await" trend recently, including rust. That other comment brought up that it exists in C# for a long time, hence not a recent trend.
I'm still annoyed that most other languages stole async/await... but not the more general monadic/do notation. Instead we get elvis operators, chaining functions, etc.
F#'s "Computation expressions" are the same sort of thing as the mentioned Haskell's "do notation" and Scala's "for comprehension". They're just thin syntactic sugar for "callbacks" -- chaining maps/binds/flatmaps/etc. Even though F#'s "Computation expressions" are very cleverly thought out and more general.
in F# it's an instance of computational expression, not keywords. So it's really only C# that added the keywords, and other languages followed suit since 2015. None of the functional languages have async/await as keywords
The `let* in` is a generic syntax for monads, it doesn't need a special one just for promise. This was in fact a debate back when async/await was in consideration for ECMAScript, but special syntax is hip so now we have `async/await` for Promise, `.?` for optionals and `flatMap` for arrays, basically the same thing.
Having seen too much `.map(_.map(` in Scala, I'd argue that different words/syntax for different things (that happen to have the same algebraic structure) is a good thing.
> It turns out Lwt gained support for let* sytax only in April 2020.
I don't understand your point. Monadic let can be done with ppx_let (created in 2016), and even before that there was the older syntax where you write `lwt` instead of `let`.
How it started: "In OCAML it's just like any other monad you use the bind operator instead. No need for special keywords."
How it's going: "well, there's a third party libary that only recently introduced let*, but before that you had to use either ppx_let [whatever that is — d.] or an older where you use lwt"
You listed no less than three special keywords. And one of them specifically introduces a new syntax via ppx.
"Just".
I find this overuse of the word "just" extremely infuriating. And FP-community is especially guilty of overusing it. "Oh, no need for X, just use <some string of smart-sounding words that is always extremely convoluted, doesn't actually do what X does, comes with caveats the length of the equator etc.>"
the point is not that there should be no special syntax, but that special syntax in these (functional) languages serves a more generic purpose, and isn't just for async.
Ocaml is actually the worst example because it has always relied on extensions to provide an alternative to Haskell's do notation.
> well, there's a third party library that only recently introduced let*
it won't change how you feel about it but `let*` is an syntax extension (ppx), kinda like babel transform. It has nothing to do with the third party library. What the library provide are async primitives, equivalent of the `q` package in nodejs
Your point about using "just" is an important one. When you're inside all of that, it seems crystal clear, but for people coming outside of that bubble, it can be quite opaque.
--- end quote ---
So, your original comment, " In OCAML it's just like any other monad you use the bind operator instead. No need for special keywords." quickly devolved into:
- oh, it's not "just a bind operator"
- oh, you need special syntax
- oh, you need a third party library that may or may not have support for that special syntax
So yeah, it's not "just <intellectually superior sounding words>". It never is.
Especially in the context of the conversation which is:
- ReScript
- Requirement to integrate and interoperate with JS and JS libraries that are increasingly Promise-based.
If you read back my comment, at one point I said I only have basic understanding of OCAML, at no point I claim to be an expert. I'm mediocre in programming in general. What I said I said it from the perspective of a javascript developer who don't think that async await is that big a deal, I just happen to know some context regarding functional programming, which, again, isn't the point of view I am taking, since I only have basic knowledge and write javascript at my day job.
With that said, let me put it bluntly, you are being annoying.
If we want to stop talking about programming and start picking on people's tone, let me point out one thing: you are not a mind reader, the way you just pick on a rather common word that people often use casually, and infer that I am asserting my "intellectually superiority", is annoying. Let me remind you this is the Internet where everyone is mostly anonymous. No one cares enough to show off to a bunch of usernames that don't matter to them.
You are right to say that what I claimed to be simple, wasn't simple, but I'm not taking the other nonsense you are accusing me of.
It is though, it's a function/operator that is defined in userland.
> - oh, you need special syntax
> - oh, you need a third party library that may or may not have support for that special syntax
No, you don't need either of these things. These just add a convenient syntax that desugars to the aforementioned bind function. These PPXs aren't special keywords specifically for async/await that had to be added into the language's syntax itself. Note that I know nothing about ReScript and this reply is not about ReScript, as that's not what this comment chain is about.
The full explanation: In OCaml, before 4.08, there was no special support for monads. For example, the Option module (https://ocaml.org/api/Option.html) offers an "Option.bind" function. When chaining monads, you would usually write "Promise.bind" for promises, "Option.bind" for options, etc. OCaml also allows you to define your own infix operators. By convention, "bind" is often associated with ">>=". But this is usually done in userland code, OCaml and its standard library don't use ">>=". For example, the Result module (https://ocaml.org/api/Result.html) uses "Result.bind" too, but doesn't define ">>=".
Lwt is one of the two popular libraries used to have asynchronous IO, the other being Async. It does this through a type called "Lwt.t", which is very close to promises in JS. Lwt.t is a monad, and to chain monads like normal code, you need to use "bind". In OCaml, you can chain expressions with ";" or "let ... in", but if you want to chain monads, you have to use "bind" or ">>=" instead. This is considered annoying by some people, and those people often want monadic code to look the same as regular code. For this, Lwt and Jane Street (the company behind Async) have syntax extensions, called "PPX". PPXs are OCaml code that is executed on your code before your code is compiled. You could call them macros. The equivalent of PPXs in the JS world would be Babel, and a single PPX would be a Babel transformer.
In 4.02, Lwt added the Ppx_lwt library, that allows you to write code that is close to regular code, but is monadic: "let%lwt ... in" instead of "let ... in". There's also ppx_let, by the people behind Async: "let%bind ... in".
That brings us to binding operators. In 4.08, OCaml added support in the base language (so no need for PPXs) for monadic let. Here's the manual page about it: https://ocaml.org/manual/bindingops.html. So now, you can write "let* ... in", which is a bit shorter, and doesn't rely on external libraries or PPXs. You can see in the manual page I linked in the 2nd and 3rd code blocks examples how this makes monadic code look more like regular code. There's also "let+ ... and+ ... in", which has support for applicative functors.
Your point about using "just" is an important one. When you're inside all of that, it seems crystal clear, but for people coming outside of that bubble, it can be quite opaque. To finish on another JS example, this story is close to the story around asynchronous code in JS. First callbacks, then promises, then syntaxic support in the language to make promise-heavy code look just like regular code. The difference here is that OCaml put a more general async/await in the language, but no promises.
To go back to ReScript, you can use promises in ReScript, but there is no syntax support for monadic code in general, or promises themselves. So this is like JS with promises but without async/await.
Doesn't this mean we're basically back to callback hell? This was one of the primary criticisms of Node before async/await was introduced.