async-interop / event-loop

An event loop interface for interoperability in PHP.
MIT License
169 stars 9 forks source link

Thoughts about merging to core #115

Closed kelunik closed 7 years ago

kelunik commented 7 years ago

One of our goals should be to merge this specification into php-src later. One of the major issues that cannot be solved in userland are automatic coroutines. We either have to return a Generator from a method or a Promise. A generator doesn't tell you whether it's really a coroutine or just a generator that's used as iterator or something else. A promise tells you it's a potentially async operation, I say potentially, because it could as well just return a already fulfilled promise. If you want to return a promise, but still use coroutines, you have to use some kind of wrapper, e.g.

<?php

function doAsync(int $foo): Promise /* <int> */ {
    return new Coroutine(function () use ($foo) {
        yield doSomethingAsync();
        return $foo;
    });
}

The future not only I'm heading to, but also @trowski and @bwoebi at least, makes PHP have at least some support for async built into core. For coroutines, that could mean turning the above example into

<?php

async function doAsync(int $foo): int {
    await doSomethingAsync();
    return $foo;
}

The plan is to use await instead of yield here to allow for future async generators, too.

If we want to build coroutines into core, we need an event loop in core. We should discuss whether our API would look the same as it's now if built into core, so it's as compatible as possible when merging the specification into core.

sagebind commented 7 years ago

The static Loop class currently, assuming we only make async loop calls through that class, I think lends itself very well to being implemented in the core. Considering languages with a loop built-in such as JavaScript, things like setTimeout() are pretty similar to Loop::delay() right now in how they are invoked statically. I could see this being a really great API for the core to adopt.

If we're looking into implementing this spec in core, I wouldn't be surprised if we run across some difficulties that might require a different API, though naturally I don't know what those might be yet.

kelunik commented 7 years ago

@sagebind That's one thing I wondered about. How JavaScript have any way to start from a clean state, e.g. for unit tests? With our current approach we can do that by configuring a new loop. How does JavaScript solve that?

sagebind commented 7 years ago

@kelunik JavaScript has no solution for that, but I don't see a great solution for us either if the Loop class is implemented by the engine directly. We would want the engine to instead implement Driver so that we could have the means of creating new event loops during runtime. I fear that could get really complicated inside the engine though. Maybe we use some sort of per-thread static struct that points to an active loop/driver instance. Loop could be the userland API for accessing those internals.

bwoebi commented 7 years ago

Well, the current Loop class has execute(), which allows a subcontext. If we retain something such, it'd work fine.

aenglander commented 7 years ago

Based on @kelunik's comment above, would it make sense to possibly start building towards a Hack implementation? It currently supports async/await which would remove the hurdle of getting async/await into the PHP code. Porting a proven solution from Hack/HHVM into PHP may be a smaller mountain to climb than starting from scratch with an issue that does not yet have an RFC.

kelunik commented 7 years ago

I'm closing this one for now, async / await isn't something to worry about in this specification, as we don't know how it will look like. Maybe green threads, maybe just implemented as syntactic sugar.