Function Forwarding – The Lazy Programmer Doesn’t Like Writing Glue Code

Back in the day, when NeXT computers roamed the earth, there was this language feature in Objective-C that I came to know and love. Objective-C has this feature called forwarding, or delegating, or whatever. The basic idea is, you call a function on an object, and if it knows the function (late bound goodness), it will execute the function. If it doesn’t, it will forward the function call to the objects ‘forward’ function, handing it all the parameters, and giving it a chance to do something, before throwing an error if nothing is done.

Well, roll forward 20 years (yah, it was that long ago), and here we are with the likes of Python, JavaScript, Ruby, and Lua inheriting the dynamic language mantle passed along from Simula and SmallTalk. So, recently, I was pining for that good ol’ feature of Objective-C, so I decided to implement it and see what it takes today.

Why? The scenario is simple. There are many instance where I want to write a ‘proxy’ of some sort or another. In one such scenario, I want to take the name of the function being called, along with the parameters for the function, wrap them up into a string, send them somewhere, and have them dealt with at that new place. At the other end, I can deal with actually applying the function and parameters.

So, beginning with this:


local baseclass = {
  func1 = function(foo, bar, bas)
    print(foo, bar, bas);
  end,

  func2 = funciton(baz, booz, bazzle)
    print("Function 2: ", baz, booz, dazzle);
  end
}

I want to be able to do the following:

local Messenger("machine.domain.com/baseclass");

Messenger:func1("this", "little", "Piggy");
Messenger:func2("Piggy", 500, false);

Tada! Done…

OK. So, let’s begin at the beginning. First of all, I want some sort of base Object/Class thing that will help make things easier. I’ll use the one from the ogle project, because it seems to be pretty decent and minimal.


-- Object.lua

local Object = {}
Object.__index = Object
setmetatable(Object, Object)

-- Variables
Object.__metamethods =  {
    "__add", "__sub", "__mul", "__div", 
    "__mod", "__pow", "__unm","__len", 
    "__lt", "__le", "__concat", "__tostring"
}

-- Metamethods
function Object:__call(...)
    return self:new(...)
end

function Object:__newindex(k, v)
    if k == "init" or getfenv(2)[k] == self then
        rawset(self, "__init", v)
    else
        rawset(self, k, v)
    end
end

-- Constructor
function Object:__init()
end

-- Private/Static methods
function Object:__metamethod(event)
    
    return function(...)
        if self:parent() == self then
            error(event .. " is unimplemented on object.", 2)
        end
        
        func = rawget(self, event) or rawget(self:parent(), event)
        if type(func) == "function" then return func(...) else return func end
    end
end

-- Methods
function Object:parent()
    return getmetatable(self)
end


function Object:new(...)
    local o = {}
    setmetatable(o, self);


    self.__index = function(self, key)
        -- See if the value is one from our metatable
        -- if it is, then return that.
        local mt = getmetatable(self); 
        local value = rawget(mt,key);
        if value then
            return value;
        end

        -- If the thing is not found, then return the 'forward' method
         local delegate = rawget(self, "__delegate") 
        if delegate ~= nil then
            return self:__delegate(key);
         end
    end


    self.__call = Object.__call
    self.__newindex = Object.__newindex
    
    for k,v in pairs(Object.__metamethods) do
        o[v] = self:__metamethod(v)
    end
    
    o:__init(...)
    return o
end

return Object;

Just a little bit of Object/behavior mixin mumbo jumbo. I’ve made a couple of mods from the original, the most interesting being the implementation of the ‘.__index’ function. The ‘__index’ function is called whenever you’ve tried to access something in the runtime that doesn’t immediately exist in the table. In the example code above, when I’m calling: ‘Messenger:func1()”, the runtime first does: something = Messenger.func1. If it finds something, and that something is a function, it evaluates the function, passing the specified parameters. If it doesn’t find something, then it will throw an error saying ‘something is nil’, and thus can not be called.

Alright, so if you look at that ‘__index’ function, the last case says; if there is a function called “__delegate” defined, then return that.

OK. So, at this point, if you create an instance of an object, and try to call a function that does not exist, it will fail because there is no ‘__delegate’ function defined. In steps the ‘subclass’.


Messenger = Object();

function Messenger:__init(target)
  self.Target = target;
  
  self.__delegate =  function(self, name, ...)
    return function(self, ...)
      local jsonstr = JSON.encode({...});
      print(name, jsonstr);
    end
  end

  return self;
end

What’s going on here? Basically, the “Messenger” is a subclass of the “Object”. The ‘__init()’ function is called automatically as part of the object/type creation. Within the ‘__init()’, the ‘__delegate()’ function is setup. Isn’t that a weird function to be called? If you go back and look at the ‘__index()’ function, you’ll notice that it returns the result of the ‘__delegate’ method right away. In this case, the ‘Messenger.__delegate()’ function will return a ‘closure’, which is a fancy word for a function enclosed in a function. This happens with iterators as well, but that’s another story. The closure, in this case, is the true workhorse of the operation. In this particular case, all it does is turn the parameters into a json string and print it out, but you can probably imagine doing other things here, like sending the parameters, along with the function name, across a network interface to a receiver, who will actually execute the code in question.

And that’s that.

Another example:


local mssngr = Messenger();
mssngr:foo("Hello", 5);

mssngr:bar("what", 'would', 1, "I", {23,14,12}, "do?");

> foo	["Hello",5]
> bar	["what","would",1,"I",[23,14,12],"do?"]

This is a great outcome as far as I’m concerned. It means that I can easily use this Messenger class as a proxy for whatever purposes I have in mind. I can create different kinds of proxies for different situations, simply by replacing the guts of the ‘__delegate()’ function.

Besides being motivated by nostalgia for Objective-C paradigms of the past, I actually have a fairly practical and immediate application. I’ve noticed that Computicles are an almost perfect implementation of the Actor pattern, and the only piece missing was a separable “Messenger” actor. Now I have one, and a mechanism to use to communicate both locally with other computicles within the same process, as well as computicles across networks, without changing any core computicle code. This makes it easier to pass data, call functions, and the like.

At any rate, discovering a fairly straight forward implementation of this pattern has been great, and I’m sure I’ll get much tremendously good usage out of it. I wonder if it can be applied to making calls to C libraries without first having to specify their interfaces…

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s