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

Add opt-in to make Promises operations #812

Open
cowboyd opened this issue Oct 31, 2023 · 3 comments
Open

Add opt-in to make Promises operations #812

cowboyd opened this issue Oct 31, 2023 · 3 comments
Milestone

Comments

@cowboyd
Copy link
Member

cowboyd commented Oct 31, 2023

Having to wrap every promise or async function in call() is doable, but a pain, and it stretches the promise that Effection makes of being a very straightforward translation from async/await.

We should have a module that makes promise an operation:

import "effection/promises-are-operations";

Or something like that.

@cowboyd cowboyd added this to the v3.1 milestone Oct 31, 2023
@davidbrochart
Copy link
Contributor

More generally, how does Effection mix with existing code bases that use promises or async functions, does it work at all?
Correct me if I'm wrong, but to make a parallel with the Python world, it seems that Effection is like Trio, a custom event-loop that cannot work with asyncio. There are projects to make them work together, like AnyIO or trio-asyncio, however.

@cowboyd
Copy link
Member Author

cowboyd commented Jun 3, 2024

@davidbrochart It's really easy to mix Effection code with Async code and vice-versa. In fact, it's a design goal. In most cases, you can use call() to call any async function. For example, here is a way to perform a fetch that is automatically cancelled when the operation passes out of scope.

import { call, useAbortSignal } from 'effection';

function* search(q) {
  let signal = yield* useAbortSignal();
  let response = yield* call(() => fetch(`https://google.com?q=${q}`, { signal }));
  return yield* call(() => response.text());
}

(Notice how we did not need to bother with the abort controller, as this is taken care of by structured concurrency)

It is possible by adding Symbol.iterator to Promise.prototype to be able to yield* directly to promises without wrapping them in call(). This effectively makes every Promise also an Operation so that you could write the above as:

import { useAbortSignal } from 'effection';

function* search(q) {
  let signal = yield* useAbortSignal();
  let response = yield* fetch(`https://google.com?q=${q}`, { signal });
  return yield* response.text();
}

We do this in the Effection test suite itself in order to make testing with promises even more concise.

While we would not want to do this by default, we might want to make it available as an opt-in for those who are ok with it.

For more information about the interoperation between the structured concurrency and async worlds see the Async Rosetta Stone

@davidbrochart
Copy link
Contributor

Thanks a lot for the details @cowboyd, very interesting!

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

2 participants