Step.js and Asynchronous Control Flow with CoffeeScript

I am trying to get Step.js library working properly with coffee-script. I am quite new to coffee but here is my attempt:

setTimeout(
  =>
    console.log("step 1 at #{new Date}")
    setTimeout(
      =>
        console.log("step 2 at #{new Date}")
        setTimeout(
          =>
            console.log("step 3 at #{new Date}")
          10000
        )
      10000
    )
  10000
)

# step 1 at Tue Nov 13 2012 13:18:51 GMT-0600 (CST)
# step 2 at Tue Nov 13 2012 13:19:01 GMT-0600 (CST)
# step 3 at Tue Nov 13 2012 13:19:11 GMT-0600 (CST)

should be the same as:

step(
  ->
    setTimeout(
      =>
        console.log("step 1 at #{new Date}")
        this(null)
      10000
    )
  ->
    setTimeout(
      =>
        console.log("step 2 at #{new Date}")
        this(null)
      10000
    )
  ->
    setTimeout(
      =>
        console.log("step 3 at #{new Date}")
        this(null)
      10000
    )
)

# step 1 at Tue Nov 13 2012 13:12:04 GMT-0600 (CST)
# step 2 at Tue Nov 13 2012 13:12:04 GMT-0600 (CST)
# step 3 at Tue Nov 13 2012 13:12:04 GMT-0600 (CST)

As you can see from the above example step is executing all the steps at the same time instead of doing them one at a time like it is supposed to. I am not too sure why that is right now.

CoffeeScript implicitly adds a return in front of the last expression in a function. This is a problem with Step, which assumes that if you return anything, that step is synchronous.

The solution is to add an explicit return at the end of each step function:

step(
  ->
    setTimeout(
      =>
        console.log("step 1 at #{new Date}")
        this(null)
      10000
    )
    return
  ->
    setTimeout(
      =>
        console.log("step 2 at #{new Date}")
        this(null)
      10000
    )
    return
  ->
    setTimeout(
      =>
        console.log("step 3 at #{new Date}")
        this(null)
      10000
    )
    return
)

Figured it out. So since coffee has implicit return statements it will return the value of the last statement (or expression if you will). Step library assumes that when you return an explicit value from the function you are doing synchronous stepping (making it easier to mix and match sync and async operations). This works great in Javascript, where we have explicit return statements.

A workaround is to always return undefined:

step(
  ->
    setTimeout(
      =>
        console.log("step 1 at #{new Date}")
        this(null)
      10000
    )
    return undefined
  ->
    setTimeout(
      =>
        console.log("step 2 at #{new Date}")
        this(null)
      10000
    )
    return undefined
  ->
    setTimeout(
      =>
        console.log("step 3 at #{new Date}")
        this(null)
      10000
    )
    return undefined
)

# step 1 at Tue Nov 13 2012 13:38:51 GMT-0600 (CST)
# step 2 at Tue Nov 13 2012 13:39:01 GMT-0600 (CST)
# step 3 at Tue Nov 13 2012 13:39:11 GMT-0600 (CST)