Lua Callbacks

davidk
Posts: 13
Joined: Wed Dec 09, 2009 7:01 pm
Location: avalon.mud.de

Lua Callbacks

Post by davidk »

Currently the functions which set callbacks like tempTimer, tempTrigger and similar take a string as callback function and compile it each time:

Code: Select all

tempTimer (0.3, [[ echo ("It is time") ]])
If you have a lot of timers running (for example in a speed walk script) this would be quite inefficient.

It would be more efficient and powerful if you could pass a function directly which only has to be compiled once. This would also enable using Lua closures. The Lua code would then look like this:

Code: Select all

tempTimer (0.3, function () echo ("It is time") end)
-- or we could use a named function:
tempTimer (0.3, f)
Syntax errors get handled a lot sooner so debugging is easier. Another advantage would be that the code block would keep the current environment, while loadstring always uses the global environment. This would break out of any sandboxes.


In order to pass the function block through the C code you can use the Lua registry (http://www.lua.org/manual/5.1/manual.html#3.5).

I am not yet familiar with the Mudlet code and I do not know when I will have the time to explore it, so I cannot give a complete patch here, but still I try to give some code that should be relatively easy to integrate. My code snippets would make the code backwards compatible, it could still handle strings. (Though I would advise to remove this backward compatibility at a later point to make sandboxes possible).

My code snippets assume that there is an object associated with the callback. Its pointer is used as key value for the registry. As an alternative you could create some unique string.

Code: Select all

CObjectWithCallback *pObject;
When setting the callback:

Code: Select all

// save the argument #1 in the registry using a pointer to the object
// associated with the callback as key
lua_pushlightuserdata (L, pObject);
lua_pushvalue (L, 1);
lua_settable (L, LUA_REGISTRYINDEX);
When calling the callback function:

Code: Select all

lua_pushlightuserdata (L, pObject);
lua_gettable (L, LUA_REGISTRYINDEX);

if (lua_isfunction (L, -1)) {
  // here we should push any arguments, if the callback function is to be supplied with arguments
  lua_call (L, 0, 0);
} else if (lua_isstring (L, -1)) {
  // for backward compatibility, handle string callbacks although I would recommend to declare this
  // as deprecated
  char *s; size_t len;
  s = lua_tolstring (L, -1, &len);
  if (luaL_loadstring (L, s) != 0) {
    // handle the error
  } else {
    // push arguments, if there are any
    lua_call (L, 0, 0);
  }
} else {
  // we should have checked the type of the argument when setting the callback, so
  // the program should never reach this
  luaL_error (L, "wrong type for callback function");
}
Last but not least, the clean up:

Code: Select all

// remove the function from the registry so the GC can deal with it
lua_pushlightuserdata (L, pObject);
lua_pushnil (L);
lua_settable (L, LUA_REGISTRYINDEX);
A similar solution could be used for the label callbacks. (Only the backward compatibility part would need to be changed). An advantage would be that anonymous functions can be used as callback and closures would be possible.

User avatar
Vadi
Posts: 4943
Joined: Sat Mar 14, 2009 3:13 pm

Re: Lua Callbacks

Post by Vadi »

Hmm... my personal worry is that this'll make it even more complicated for novice coders, although I suppose it's worth it for the sake of efficiency.

Thanks a ton for the detailed explanation, it seems reasonable to change.

User avatar
Vadi
Posts: 4943
Joined: Sat Mar 14, 2009 3:13 pm

Re: Lua Callbacks

Post by Vadi »

Well, Heiko never posted on the weekend yet but said there was some reason "back then" as to why we went with strings instead of functions, but he can't remember it now.

We used to have other forums before, trying to recover them now to find the reason (along with suggestions we had for the mapper :| ) and then we could see if the reason is still valid today.

User avatar
Heiko
Site Admin
Posts: 1548
Joined: Wed Mar 11, 2009 6:26 pm

Re: Lua Callbacks

Post by Heiko »

I'll add your proposal as I believe that it is certainly useful for advanced Lua users. The default will stay what it is, however, as this issue has been ferociously debated in the beginning of Mudlet and the final consensus was that the current approach is much easier to understand. Keep in mind that many users of Mudlet are new to programming and Lua in particular.

User avatar
Heiko
Site Admin
Posts: 1548
Joined: Wed Mar 11, 2009 6:26 pm

Re: Lua Callbacks

Post by Heiko »

This has been added to tempTimer in latest git. Will be added to tempTriggers and label callbacks in the future.

guy
Posts: 26
Joined: Wed Mar 03, 2010 5:41 am
Location: Seattle

Re: Lua Callbacks

Post by guy »

There isn't a reason not to have both. E.g. a check to see whether the parameter is a string or a function reference would be backwards compatible, yet allow those tasty anonymous functions...

User avatar
Vadi
Posts: 4943
Joined: Sat Mar 14, 2009 3:13 pm

Re: Lua Callbacks

Post by Vadi »

This is now available with 1.1.0.

guy
Posts: 26
Joined: Wed Mar 03, 2010 5:41 am
Location: Seattle

Re: Lua Callbacks

Post by guy »

It appears that label callbacks can't be functions contained in a table. testcallback1() doesn't create the expected behavior from its label, but testcallback2() does. This really limits the prevention of namespace pollution when distributing packages.

Also, the callbacks can't be named functions. Is that something that only timers get?? If so, labels need it too!

I'm using the March 8 build of 1.1.0 on linux 64bit.

Code: Select all

aTable = {}
function aTable.callback ()
   echo("Hi there cheesewiz\n")
end

function anotherCallback ()
   echo("Go find a horse\n")
end

function testcallback1 ()
   createLabel("testlabel1", 20,20,40,40,1)
   setBackgroundColor("testlabel1", 0,0,190,200)
   setLabelClickCallback("testlabel1", "aTable.callback", 8)
end

function testcallback2 ()
   createLabel("testlabel2", 20,60,40,40,1)
   setBackgroundColor("testlabel2", 0,190,0,200)
   setLabelClickCallback("testlabel2", "anotherCallback", 8)
end

Golem
Posts: 30
Joined: Thu Feb 07, 2013 6:46 pm

Re: Lua Callbacks

Post by Golem »

Right, sorry for digging this up but: have callbacks been added to tempTrigger and it's companions?
They do work for tempTimer, but it does not seem they do for triggers.

User avatar
Vadi
Posts: 4943
Joined: Sat Mar 14, 2009 3:13 pm

Re: Lua Callbacks

Post by Vadi »

They haven't been yet. Still on the list of desired things however.

Post Reply