b/c it gives you a controlled way to break the rule “child tasks end before parent tasks”.
I think what the issue here is, what you mean by “task”: do you mean a function (or “method”), or do you mean a coroutine (or “fiber”)? In Polyphony, fibers always end before parent fibers, but you can start a fiber in a method and it will be limited to the lifetime of its parent fiber rather than the method itself, so it can continue running after the method call has returned. Polyphony has no concept of nurseries. There’s just a hierarchy of fibers, but you can always make sure any fibers spawned in nested method calls are done by the time the call returns by doing this:
def some_method
spin { ... }.await
end
The fiber created in order to wrap whatever operation is being done acts as a de-facto nursery, and you can pass it around just like a nursery. It seems to me that it’s just a case of differing default behaviors, but you can achieve the same behavior in both Trio and Polyphony.
BTW, how are you handling error propagation?
Any uncaught exception is going to cause the termination of the current fiber, and will propagate up the fiber hierarchy until a suitable exception handler is found. Since child fibers are always spun on the same thread as the parent fiber, so if the child fiber is running that means the parent fiber is either suspended or waiting to be resumed. The error propagation mechanism simply schedules the parent fiber with the exception, causing it to be raised eventually in the context of the parent fiber once it is resumed.
As I already mentioned, the parent can not have terminated without first terminating all child fibers. In Polyphony, one needs to explicitly wait for child fibers, otherwise any child fiber will be terminated when the parent fiber is done running. There are multiple ways to wait for child fibers: Fiber#await_all_children
, Fiber.await(...)
, Fiber.select(...)
, suspend
, sleep
… There’s also a #supervise
method that allows waiting for all child fibers and optionally restarting them if they fail with an exception.
So this is also an area where there’s a difference in default behavior. In Trio, the default behavior is a nursery waits for all child tasks to terminate. In Polyphony, the default behavior is you don’t wait, but you can wait for all child fibers if you need to.
Does this make sense to you?