Skip to content

Commit

Permalink
more comments and commentary
Browse files Browse the repository at this point in the history
  • Loading branch information
maxtaco committed Jan 24, 2012
1 parent 3a8fbfe commit b8d3e72
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 6 deletions.
38 changes: 35 additions & 3 deletions TAME.md
Expand Up @@ -279,19 +279,51 @@ file `nodes.coffee`.

### Awaits Can work as Expressions

*In a rush*
I don't really like this feature, but people have requested it, so
here goes a trip down the rabbit hole. It's possible to use `await`
blocks as expressions. And recursively speaking, it's possible to use
statements that contain `await` blocks as expressions.

An `await` block takes the value of its first `defer'ed slot.
The simple rule is that an `await` block takes on the value of the
`defer` slot named `_` after its been fulfilled. If there
are multiple `defer` slots named `_` within the `await` block, then
the last writer wins. In practice, there's usually only one. Thus:

```coffeescript
add = (a,b,cb) ->
await setTimeout defer(), 10
cb(a+b)

x = (await add 3, 4, defer()) + (await add 1, 2, defer())
x = (await add 3, 4, defer _) + (await add 1, 2, defer _)
console.log "#{x} == 10"
```

Of course, things can get arbitrarily compicated and nested, so it
gets hairy. Consider this:

```coffeescript
x = await add (await add 1, 2, defer _), (await add 3, 4, defer _), defer _
```

The rule is that all nested `await` blocks (barf!) are evaluated
sequentially in DFS order. You will get `10` in the above example
after three sequential calls to `add`.

I really don't like this feature for two reasons: (1) it's tricky to
get the implementation right, and I'm sure I haven't tested all of the
corner cases yet; (2) it's difficult to read and understand what
happens in which order. I would suggest you save yourself the heartache,
and just write the above as this:

```coffeescript
await add 1, 2, defer l
await add 3, 4, defer r
await add l, r, defer x
```

It's just so much clearer what happens in which order, and it's easier
to parallelize or serialize as you see fit.

## Translation Technique

The CoffeeScript tame addition uses a similar continuation-passing translation
Expand Down
13 changes: 10 additions & 3 deletions src/nodes.coffee
Expand Up @@ -239,16 +239,23 @@ exports.Base = class Base
# AST Walking Routines for CPS Pivots, etc.
#
# There are three passes:
# 3. Find await's and trace upward.
# 4. Find loops found in #1, and flood downward
# 5. Find break/continue found in #2, and trace upward
# 1. Find await's and trace upward.
# 2. Find loops found in #1, and flood downward
# 3. Find break/continue found in #2, and trace upward
#

# tameWalkAst
#
# Walk the AST looking for taming. Mark a node as with tame flags
# if any of its children are tamed, but don't cross scope boundary
# when considering the children.
#
# The paremeter `p` is the parent `await`. All nodes beneath the
# first `await` in a function scope should point to its highest
# parent `await`. This is so in the case of nested `await`s,
# they're really pulled out and run in sequence as the level of the
# topmost await.
#
tameWalkAst : (p) ->
@tameParentAwait = p
for child in @flattenChildren()
Expand Down

0 comments on commit b8d3e72

Please sign in to comment.