Arc Forumnew | comments | leaders | submitlogin
And a Functional Implementation of dynamic-wind (
2 points by aw 2156 days ago | 3 comments

3 points by jsgrahamus 2156 days ago | link

What is dynamic-wind and why is it important?

Thanks, Steve


4 points by rocketnia 2154 days ago | link

Are you familiar with continuations? Continuations are essentially snapshots of the call stack. By calling (ccc ...), you take a snapshot. By calling the snapshot with a value, you jump back to that old stack -- right at the position of the (cc ...) call -- and return a different return value than before.

This is a pretty weird behavior, but it can useful for avoiding the inversion of control dilemma in imperative code. That is, if code A and B need to communicate, should code A call code B, or should code B call code A? Sometimes the callee side becomes a mess of callbacks, rather than a direct imperative style. With continuations, both sides can be the caller, and neither side needs to be the callee: When A calls B with a value, we resume B's earlier call to A using that value as the result. This approach doesn't make it straightforward to design communication paths that work like this, but it is a building block.

Unfortunately, jumping around with continuations messes up another common imperative coding technique. If people write code to set up and tear down a resource, they often like to write all the code in the middle in a way that assumes that resource is already available. With continuations, that assumption can be incorrect: If you jump out of the code in the middle, you may have just skipped the tear-down code entirely. If you jump into the middle, you may have just skipped the setup code.

Dynamic-wind makes up for that shortcoming by letting you write a structured code block that always executes its setup and tear-down sections, even if it's entered or exited using a continuation jump. So when you do a jump, you might actually go through a few dynamic-wind handlers before you reach your destination.

If you're more familiar with exceptions, continuations and dynamic-wind can be seen as a companion of exceptions and "try { ... } finally { ... }" blocks. An exception throw is a jump to an outer level of the stack, but the jump may stop to execute a few "finally" sections before it reaches its destination.

In Arc (and Scheme), continuations and exceptions are supported in the same language. They're both the same kind of jump, executing all the same handlers in between; the "finally" handlers and "tear-down" handlers are basically the same kind of handler. In Arc, unless you write custom Racket code to invoke Racket's dynamic-wind directly, Arc has no way to write a setup handler, but there is an (after ...) construct for writing a finally/tear-down handler.

I think what I've called "setup" and "tear-down" are more commonly called winding and unwinding handlers, or before and after sections. I picked the terms "setup" and "tear-down" just in the hopes of painting a more concrete picture of why they're useful.

This has still been a pretty quick explanation relative to the complexity of the topic, and I haven't included even a single example. If you still have unresolved questions, that's absolutely understandable. :)


2 points by jsgrahamus 2153 days ago | link

Thank you.