Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CS2 Discussion: Features: Shorter syntax for defining promises and async/await #4953

Closed
coffeescriptbot opened this issue Feb 19, 2018 · 7 comments

Comments

@coffeescriptbot
Copy link
Collaborator

coffeescriptbot commented Feb 19, 2018

From @mitar on 2016-12-12 03:53

I believe CoffeeScript could have a simpler syntax to use async/await. With coffeescript6/discuss#10 and #3757 initial support for that was merged in, but I think more could be done.

Here are some my previous thoughts on the subject, but here I am proposing another iteration of those thoughts.

I see three issues with current async/await and promises state in JavaScript:

  1. we had callback hell, now we have new Promise (resolve, reject) => hell
  2. having to think which function is async and which is not and then use wait properly (CoffeeScript makes it defining easier by adding async keywords automatically to functions if they use await, but then it is harder to know when should one call a function with await)
  3. have code full of await keywords around

To address the point 1. I would suggest the ~> operator for defining functions which return a promise:

fetch = (url) ~>
  request url, (error, response, body) ->
    resolve error if error
    reject body

Would be compiled into:

var fetch;
fetch = function(url) {
  return new Promise(function (resolve, reject) {
    request(url, function(error, response, body) {
      if (error) {
        reject(error);
        return;
      }
      resolve(body);
      return;
    });
  });
};

I am not sure if ~> should bind this or not, I think it probably should inside another function, and not for class methods. resolve and reject would be forbidden to define by the developer inside ~> function. Calling resolve or reject always returns. If you do not want to do that, you should use new Promise manually.

If you simply want to create a promise, and not a function which returns a promise, you can do:

google = do ~>
  request 'https://www.google.com', (error, response, body) ->
    resolve error if error
    reject body

So google now is a promise with content of Google's home page.

The reason why ~> is a function which returns a promise and not just returns a promise is so that it is clear that it does not call start the promise, but that you have to call it, to start it. But we could also use ~> as a shorthand for new Promise only.

Anyway, we still have await all around the code. For that I suggest we further extend ? operator. We already use it to be able to say "if this is a function, call it", we can also say "if this is a Promise, await it".

Currently, the following:

fetch?()

Gets compiled into:

if (typeof fetch === "function") {
  fetch('https://www.google.com');
}

And I suggest it gets turned into:

var temp;
if (typeof fetch === "function") {
  temp = fetch('https://commons.tnode.com');
  if (temp && typeof temp.then === "function") {
    await temp;
  }
}

The side-effect of this change would be that using ? in a function would make then all functions aync? Hmm. Maybe we need another symbol for this. But I would love to have a symbol which would call a function as await with something shorter than await.

I really think caller should not care how is a function implemented. So that they can just call a function and get the result, async or not.

What would be a drawback of making all functions async?

@coffeescriptbot
Copy link
Collaborator Author

From @DomVinyard on 2016-12-12 16:31

What would be a drawback of making all functions async?

Good question, I have a couple too... are resolve and reject the best options? Could return and throw be repurposed?

@coffeescriptbot
Copy link
Collaborator Author

From @mitar on 2016-12-12 19:10

Could return and throw be repurposed?

I was thinking about that as well. The issue is that what if there are some nested normal functions defined inside of a ~> ? How you know if you are resolving outside function or just returning inside one?

@coffeescriptbot
Copy link
Collaborator Author

From @DomVinyard on 2016-12-13 10:07

Under your proposal, every function resolves doesn't it?

@coffeescriptbot
Copy link
Collaborator Author

From @mitar on 2016-12-13 10:07

No, why would it?

@coffeescriptbot
Copy link
Collaborator Author

From @DomVinyard on 2016-12-13 14:48

I really think caller should not care how is a function implemented. So that they can just call a function and get the result, async or not.

If all functions are async, all functions must resolve, no?

@coffeescriptbot
Copy link
Collaborator Author

From @mrmowgli on 2016-12-14 08:57

@mitar: I really like your proposal for promises, especially since this is a very common paradigm!

fetch = (url) ~>
  request url, (error, response, body) ->
    resolve error if error
    reject body

By default I think we should avoid adding keywords like async/await for every function as a default. Perhaps we can split each of these feature requests into it's own issue?

@coffeescriptbot
Copy link
Collaborator Author

From @mitar on 2016-12-14 09:01

If all functions are async, all functions must resolve, no?

Or reject, which then await turns into an exception.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant