Skip to content

Navigation Menu

Sign in
Sign up

When should we dispatch - suspend/resume/switch event? #31

fgmccabe started this conversation in Ideas
Discussion options

Dispatching on an event refers to executing the equivalent of a case analysis depending on the specifics of the event. The fibers proposal switches on both suspend and on resume, the typed continuations proposal switches on a suspend but not a resume.

The motivation for 'event analysis' is that suspending and resuming must also account for the different circumstances of those events: why are you suspending and why are you resuming?

Switching on both types of events is arguably more symmetric. However, one could also imagine a system where no event analysis occurs on switching.

You must be logged in to vote

Replies: 4 comments 3 replies

Comment options

What are some concrete use cases where differentiating between multiple resumption events would be useful?

You must be logged in to vote
1 reply
Comment options

"Canceling" rather than resuming the computation comes up a lot. This one is expressible with exceptions (if there's a "throw this on another stack" instruction), but back when we first proposed a stack-switching design based on EH I remember we received multiple requests to not depend on EH (though unfortunately I cannot remember the reasons at this point).

In various message-passing systems, all messages have a tag and a payload, and a receiver waiting on a channel for a message is generally set up to branch on the tag of the message.

In bidirectional algebraic effects, there are examples such as mutating generators. With these, the generator yields values to the consumer, and after processing that value the consumer can choose to mutate the data structure being iterated over, e.g. with a "remove" event or with a "replace" event, where the latter has a payload with the value to replace the element with.

In languages with generics, it is useful to have both a boxed and unboxed version. The unboxed version works when both the sender and receiver are aware the type at hand is unboxable; the boxed version is the general-purpose option.


Some useful context is that dispatching on events seems to incur no additional overhead if you don't use it. That is it seems to be a pay-as-you-go feature.

Comment options

All signatures of control abstractions that we care about are function-like. The suspension-time dispatch selects the function, but after that its return type is fixed.

The only obvious case of an alternate resumption is cancellation. Since we already have exceptions, exception-aware code already needs to have unwinding clean-up paths that deal with those. Stack cancellation essentially has to do the same. Hence, it would seem ill-advised to introduce and use yet another mechanism for this purpose – then all code would have to guard against two kinds of abortions, in two different ways, which is unnecessarily complicated and brittle. So, injecting exceptions seem like the obvious choice for expressing cancellation.

I have seen no convincing use case for other dispatch upon resumption. Yes, there can always be cases where one "function" in a "control signature" returns a union. But that is true for regular functions as well, without anybody suggesting that we replace function calls with a bidirectional message passing system as the basic mechanism.

You must be logged in to vote
1 reply
Comment options

Yeah, I would be interested in seeing some use cases other than cancellation for alternative resumption modes as well.

I had previously been thinking that having bidirectional event dispatch was necessary for designs that want to maintain a stable reference identity across multiple resumptions, but this isn't necessarily the case. As long as the function type associated with the continuation doesn't change over the lifetime of the underlying stack resource, you could have both stable identity and unidirectional dispatch. This might force the argument type to be a wider union than it otherwise would be, but maybe that's fine.

Comment options

It seems that, whatever the choice is, it should be made consistently across all (or nearly all?) context-switching operations.

If we want to avoid requiring intermediary constructions (e.g. mutable state and/or boxing) for communication, then clearly dispatching is more "expressive". So it would seem like an artificial imposition to allow it in only one direction (e.g. when suspending) but not others (e.g. when resuming or when switching), unless there's some performance consideration.

But on the performance front, most examples involve both a suspend and a resume on typical exchanges (e.g. yield a value and then resume for the next value). So it would seem inconsistent to say that dispatching is too expensive for one direction but not for the other (especially since the dispatch and context switch for both directions would be implemented nearly identically) when it's going to happen in most exchanges if either direction supports it.

Another consideration to keep in mind is that for the systems targeting linear-memory wasm it seems likely to be a significant advantage if all live fibers/continuations/whatevers can be stored in the same table. (For example, some teams have indicated that they will want to scan all live stacks for roots during garbage collection.) That makes it problematic if continuations suspended for different reasons (e.g. cuz they just sent a message and are waiting to be resumed or cuz they are waiting to receive a message) need to have different types. Thus, for pragmatic reasons, if we do decide to support communication during switching, we will likely need to support dynamic checks for this anyways. (And that isn't hard to generalize to a dispatch.)

This analysis seems to suggest there are three consistent design options:

  1. No support for communication during switching.
  2. Communication can be checked but not dispatched, regardless of direction.
  3. Communication can always dispatch (and check), regardless of direction.
You must be logged in to vote
0 replies
Comment options

It seems that, whatever the choice is, it should be made consistently across all (or nearly all?) context-switching operations.

That is presuming a symmetry that doesn't actually exist. It is the very nature of suspend and resume that they are an asymmetric pair of operations. They have different behaviours and properties, and they are used very differently in practice. Just like call and return.

In particular, control can be passed to a resume in two different ways: via an event or via a regular return. That is not the case for suspend! And that is the only reason why we ultimately need some form of dispatch on resume. This reason does not apply to suspend.

You must be logged in to vote
1 reply
Comment options

That is presuming a symmetry that doesn't actually exist.

I do not believe I presumed any symmetry. You responded to the opening statement without responding to the following paragraphs providing the arguments supporting that statement. Symmetry does not seem to play a critical role in those arguments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /