jashkenas / coffeescript

Unfancy JavaScript
https://coffeescript.org/
MIT License
16.49k stars 1.99k forks source link

CS2 Discussion: Features: Callback hell solution: backcalls #4957

Closed coffeescriptbot closed 6 years ago

coffeescriptbot commented 6 years ago

From @celicoo on 2016-12-12 23:45

Would be great if we had backcalls as livescript:

CS6:

item, index <- someArray.forEach
console.log item

ES6:

someArray.forEach(function(item, index) {
  console.log(item);
});
coffeescriptbot commented 6 years ago

From @mitar on 2016-12-13 03:02

I do not like this. It goes against the CoffeeScript indentation semantics. Why would this:

item, index <- someArray.forEach
console.log item

Be clearer than:

someArray.forEach (item, index) ->
  console.log item
coffeescriptbot commented 6 years ago

From @edemaine on 2016-12-13 03:32

I'm no expert, but I think the idea is to avoid deep nesting of callbacks. Instead of the current

$.get 'ajaxtest', (data) ->
  $('.result').html data
  $.get 'ajaxprocess', data, (processed) ->
    $('.result').append processed

you could write

data <- $.get 'ajaxtest'
$('.result').html data
processed <- $.get 'ajaxprocess', data
$('.result').append processed

(based on an example from LiveScript docs)

This seems neat, but I wonder about two things: how do you specify which argument to put the callback (LiveScript uses _ to specify this, which conflicts with Underscore and CS REPL...), and how do you deal with error callbacks? (I don't see what LiveScript does with error callbacks... maybe not a big deal?)

One other thing: the operator @celicoo is proposing is apparently <-! from LiveScript. There are also <-, <~, <--, <~~, which are all unindenting versions of the corresponding right-arrow operator...

coffeescriptbot commented 6 years ago

From @lydell on 2016-12-13 06:09

jashkenas/coffeescript#2762

coffeescriptbot commented 6 years ago

From @DomVinyard on 2016-12-13 09:56

I'm no expert, but I think the idea is to avoid deep nesting of callbacks

async/await

coffeescriptbot commented 6 years ago

From @edemaine on 2016-12-13 15:03

@lydell Nice find. Presumably, any discussion should continue over there.

@DomVinyard I'm still learning Promises/async/await (I was corrupted too early by IcedCoffeeScript and now I can't figure it out). Can the example above be written cleanly with async/await? It definitely can with IcedCoffeeScript:

await $.get 'ajaxtest', defer data
$('.result').html data
await $.get 'ajaxprocess', data, defer processed
$('.result').append processed

Hopefully I'm not too biased toward IcedCoffeeScript which I already know, but to me this feels a lot more clear notationally, in particular which argument is the callback. Also you can do awesome things like await for ... defer which you couldn't do with <- as I understand it.

coffeescriptbot commented 6 years ago

From @celicoo on 2016-12-13 16:28

@mitar The main idea of backcalls is to avoid callbacks hell, as the title (and @edemaine) suggest, i use Livescript and it is fantastic.

@DomVinyard I don't think it's necessary to compare backcall's benchmark to async/await to know that backcalls are definitely faster, once it doesn't generate any kind of code, it's just pure callbacks.

coffeescriptbot commented 6 years ago

From @mitar on 2016-12-13 19:24

Hm, so if the idea is just to remove indentation level, maybe we could just have an operator for that? Like:

someArray.forEach (item, index) -> \
console.log item
coffeescriptbot commented 6 years ago

From @nilskp on 2016-12-14 16:40

Any callback is trivially converted into a Promise.

To use @edemaine's example:

$.get 'ajaxtest', (data) ->
  $('.result').html data
  $.get 'ajaxprocess', data, (processed) ->
    $('.result').append processed

That could be rewritten into:

new Promise (cb) -> $.get 'ajaxtest', cb
.then (data) ->
  $('.result').html data
  new Promise (cb) -> $.get 'ajaxprocess', data, cb
.then (processed) ->
  $('.result').append processed
coffeescriptbot commented 6 years ago

From @mitar on 2016-12-14 19:53

Any callback is trivially converted into a Promise.

Not if the first argument of the callback is an error.

coffeescriptbot commented 6 years ago

From @nilskp on 2016-12-14 20:03

@mitar, why not? Can you give an example?

coffeescriptbot commented 6 years ago

From @mitar on 2016-12-14 20:06

I mean, if you just blindly pass promise's resolve as a callback to an API, which passes an error as the first argument, then your promise will resolve with an error, and never reject correctly.

coffeescriptbot commented 6 years ago

From @nilskp on 2016-12-14 20:09

Of course. Nothing should be done blindly. It has to match the method signature.

coffeescriptbot commented 6 years ago

From @mitar on 2016-12-14 20:15

So, can you show the above example of converting to Promises with function calls which expect node.js style callbacks with errors as first arguments? Maybe then is clearer why backcalls are cleaner.

coffeescriptbot commented 6 years ago

From @nilskp on 2016-12-14 20:17

I'm not familiar with node.js style callbacks. If you provide an example, I'll rewrite it to promises, and we can see if it's doable.

coffeescriptbot commented 6 years ago

From @nilskp on 2016-12-14 20:23

Here's a couple of ways I can think of:

# Function type 1
fOne = (value, cb) -> # something

new Promise (cb) -> fOne 42, cb
.then (error, result) ->
  if error? then alert "Oh noes: #{error}"
  else alert result

# or

new Promise (cb) -> fOne 42, cb
.then (errorOrResult) ->
  if resultOrError instanceof Error then alert "Oh noes: #{resultOrError}"
  else alert result

alternatively:

# Function type 2
fTwo = (value, errCB, resCB) -> # something

new Promise (resCB, errCB) -> fTwo(42, errCB, resCB)
.then (result) -> alert result
.catch (err) -> alert "Oh noes: #{err}"
coffeescriptbot commented 6 years ago

From @DomVinyard on 2016-12-15 15:24

Vote to close with no action

coffeescriptbot commented 6 years ago

From @GeoffreyBooth on 2016-12-19 07:51

Reminds me a lot of https://github.com/jashkenas/coffeescript/pull/4144, with many of the same issues that that proposal had.

coffeescriptbot commented 6 years ago

From @Inve1951 on 2017-07-27 03:41

4144 feels a lot better imo

coffeescriptbot commented 6 years ago

From @cloudle on 2017-10-07 16:24

Really love to see jashkenas/coffeescript#4144. It definitely should be on CS2.. pipe really shine on many other places.