Closure scheduler/ sequencer: for coding easy behaviours (ie AI behaviours)

@yojimbo2000 - what you are calling a function baker is technically called a closure, and they are very useful, I agree. The Lua docs have some good examples.

Don’t you love it when you write some code, and it works, but for a completely different reason to why you thought it was working?

Oh yes, I’ve done that more than once :stuck_out_tongue:

One of the things I’ve gleaned from reading about lua on the web is that coroutines and closures seem to be regarded as the real strengths of the language. Both can be thought of as functions-with-memory.

I use a closure in my utf8 library to iterate over characters. The point of using the closure is that the iterator can remember where the previous invocation was and therefore return the next character.

As mentioned above, I use coroutines in my Penrose Tile program because I have something that I want to do which takes a long time (compared to the ideal frame rate). So I want to split it up over frames, but I don’t want to have to set it up and tear it down each time. Using a coroutine allows me to pause the task, return control to the draw function, and then resume it on the next cycle. I can then have several processes happening effectively simultaneously and each handles its own state so the central delegator doesn’t have to know the fiddly details of what each is doing. So coroutines are useful when you have things happening that aren’t necessarily in sync with the main draw cycle.

Coroutines are also very powerful when working with iterators. Last year, I was working on something that involved iterating over some stuff that wasn’t numerical. That is, there wasn’t an easy way to say what the kth term was in the list, but given the kth term it was easy to work out what the k+1th term should be. So again I wanted to remember the previous term, work out the next one, and then do something with that term. Once I’d done whatever I wanted to do, I’d start again. With a coroutine, this was so simple because I could “return” from the middle of a loop or a recursive function call no matter how deep it was.

Here’s a snippet of the code.

function deep_copy_into(t,tt)
   tt = tt or {}
   for k,v in ipairs(t) do
      if type(v) == "table" then
         table.insert(tt,deep_copy_into(v))
      else
         table.insert(tt,v)
      end
   end
   return tt
end

function __subset(t,r,n)
   if n == 0 then
      coroutine.yield(deep_copy_into(r))
   else
      for j=1,2 do
         table.insert(r[j],t[n])
         __subset(t,r,n-1)
         table.remove(r[j])
      end
   end
end

function subsets(t,n)
   n = n or table.getn(t)
   return coroutine.wrap(function() __subset(t,{{},{}},n) end)
end

The first function is a utility function, it copies one table into another, recursing into subtables (the assumption is that every table is an honest table – not a class – and every non-table is something like a string or number that can be copied with no side effects).

The second two functions are the key. The second sets up the coroutine, the first is the one that does the work. Note that what it does is either it yields the coroutine or it calls itself after modifying its arguments. So it keeps calling itself until it hits the condition for the coroutine yield, whereupon it returns control to the original calling function without needing to work back through all the iterated calls. Then when the calling function wants the next term, it resumes the coroutine which picks up where it left off.

The recursion combined with the need to remember where you are make this ideal for coroutines.

@LoopSpace - thanks for sharing that.

I have used coroutines to spread a long setup process over several frames, so the program doesn’t appear to freeze.

And since you can’t stop and start any process faster than once per frame (well, you can, but it’s unlikely you’d would), this seems to be the obvious use of coroutines - spreading a job over multiple frames.

I also have used coroutines for precisely that purpose, in my sorting algorithms demo:

https://gist.github.com/anonymous/2bada54b7a7fb11243d1

This is somewhat unrelated to Codea, but another area where coroutines are very useful - is server-side scripting. For example, Openresty server ( http://openresty.org ) uses coroutines to run several concurrent Lua scripts that service web requests, all inside a single-threaded nginx worker process.

As well as saying that a closure is a mini-class, looking at the Codea’s class code, it uses a closure to create each instance of a class (I think?)

    -- expose a constructor which can be called by <classname>(<args>)
    local mt = {}
    mt.__call = function(class_tbl, ...)
        local obj = {}
        setmetatable(obj,c)

the __call function is a closure, which remembers both the local obj table, and the upvalue local c metatable (or does setmetatable create its own independent copy of c?).

-- Class.lua
-- Compatible with Lua 5.1 (not 5.0).

function class(base)
    local c = {}    -- a new class instance
    if type(base) == 'table' then
        -- our new class is a shallow copy of the base class!
        for i,v in pairs(base) do
            c[i] = v
        end
        c._base = base
    end

    -- the class will be the metatable for all its objects,
    -- and they will look up their methods in it.
    c.__index = c

    -- expose a constructor which can be called by <classname>(<args>)
    local mt = {}
    mt.__call = function(class_tbl, ...)
        local obj = {}
        setmetatable(obj,c)
        if class_tbl.init then
            class_tbl.init(obj,...)
        else 
            -- make sure that any stuff from the base class is initialized!
            if base and base.init then
                base.init(obj, ...)
            end
        end
        
        return obj
    end

    c.is_a = function(self, klass)
        local m = getmetatable(self)
        while m do 
            if m == klass then return true end
            m = m._base
        end
        return false
    end

    setmetatable(c, mt)
    return c
end