Mark Hamburg | 9 Feb 17:53

Lua optimization (musing)

I was reading one of the Haller and Odersky papers on event-based actors and was thinking about how their
example would translate to Lua. This is what I came up with for their Counter example:

    function makeCounter( value )
        return makeActor( function( mbox ) -- Make an actor passing its mailbox to its handler code
            while true do
                mbox:receive{
                    Increment = function() value = value + 1 end,
                    Value = function( dst, msg ) dst:send( msg or 'Result', value ) end,
                    Lock = function( dst, msg )
                        dst:send( msg or 'Result', value )
                        mbox:receive{
                            Unlock = function( v ) value = v or value end
                        }
                    end
                }
            end
        end )
    end

The Increment message increments the counter. The Value message delivers the value to a particular
mailbox. The Lock message delivers the value to a particular mailbox and waits for an Unlock message. It's
the change in behavior after the Lock message that makes the message handling different from a simple
object model. Haller and Odersky allow unhandled messages to sit in the mailbox, but that's not what I'm
worrying about here.

Rather I'm worrying about code clarity and optimization.

On the clarity front, I think it actually does fairly well. It's a little bit noisy with all of the explicit
uses of "function" for short operations, but the current lambda expression proposals wouldn't really
help with that. The more annoying part is the need for a comma after each "end". All in all, though, it's
probably fairly workable.

The problem is that every iteration of the outer loop generates three new closures and a new table and the
inner receive generates a new closure and a new table. Some of this could be mitigated with a looping
construct for the outer receive that would use the same table repeatedly, but that wouldn't address the
inner receive problem.

The optimized version looks more like:

    function makeCounter_optimized( value )
        return makeActor( function( mbox ) -- Make an actor passing its mailbox to its handler code
            local lockedReceive = {
                Unlock = function( v ) value = v or value end
            }
            local mainReceive = {
                Increment = function() value = value + 1 end,
                Value = function( dst, msg ) dst:send( msg or 'Result', value ) end,
                Lock = function( dst, msg )
                    dst:send( msg or 'Result', value )
                    mbox:receive( lockedReceive )
                end
            }
            while true do
                mbox:receive( mainReceive )
            end
        end )
    end

The control flow is now more scattered and the overall effect seems less clear. It might be approaching a
reasonable format for a state machine, but it feels like it has lost something compared to the first version.

So, the questions I'm musing over are:

	* Is there a better way to write this in stock Lua?
	* If one were to make changes to Lua to try to get both clarity and efficiency, what would those changes be?

I've got a few thoughts on the latter but nothing clear enough to propose at this time.

Mark


Gmane