Callback argument handling

setArgs and getArgs - by Mikk -
setArgs() and getArgs() are used to remember and retreive arguments for callback functions in a reasonably memory-efficient way. Note however that if your callback argument list typically is longer than 2 arguments, it is both more CPU and memory efficient to simply use an integer-indexed subtable and table.unpack.
 setArgs(myTable, "name", list,of,arguments,...)
 list,of,arguments,extra,arguments,... = getArgs(myTable, "name"[, extra, arguments, ...])
== setArgs Parameters ==
=== Arguments ===
:(myTable, "name", list,of,arguments,...)
:;myTable : Table - where to store the arguments
:;"name" : String - prefix to give the arguments, if you are storing arguments for multiple callbacks, otherwise ""
:;... : List of arguments to be stored
=== Returns ===
:nothing
== getArgs Parameters ==
=== Arguments ===
:(myTable, "name"[, ...])
:;myTable : Table - where to retreive the arguments from
:;"name" : String - prefix used in setArgs
:;... : (optional) - extra arguments to use after the stored ones
=== Returns ===
:All arguments stored by setArgs(), optionally followed by the extra arguments supplied to getArgs()
== Example 1 ==
Just demonstrating how setArgs and getArgs actually work
 function out(...)
 for i=1,select("#", ...) do
 print(i.."="..tostring(select(i,...)))
 end
 end
 
 tbl = {}
 
 setArgs(tbl, "myArgList", "a", nil, "3")
 out( getArgs(tbl, "myArgList", "extra", nil, "cheese") )
====Result====
 1=a
 2=nil
 3=3
 4=extra
 5=nil
 6=cheese
== Example 2 ==
Demonstrating how callbacks could be implemented in a "library" / addon that wants to be able to accept callback registrations from other sources
=== "Library" ===
 local mytable = {}
 local function myUpdateHandler(this, delay)
 if mytable.callback then
 	mytable.callback( getArgs(mytable, "arg", delay) )
 end
 end
 
 function RegisterOnUpdateCallback(func, ...)
 mytable.callback = func
 setArgs(mytable, "arg", ...)
 end
(There obviously needs to be a frame created that calls myUpdateHandler via OnUpdate also, but that's out of scope for the example)
=== "User" ===
 function MyMod:OnUpdate(delay)
 print("OnUpdate fired after " delay " seconds");
 end
 
 function MyMod:Initialize()
 SetOnUpdateCallback(MyMod.OnUpdate, self)
 end
==Code==
 local getArgs
 do
 local numargs
 local function _get(t, str, i, ...)
 	if i<=numargs then
 		return t[format("%s%d", str, i)], _get(t, str, i+1, ...)
 	end
 	return ...
 end
 		
 function getArgs(t, str, ...)
 	numargs = t[str.."#" or 0]
 	return _get(t,str,1, ...)
 end
 end
 
 local function setArgs(t, str, ...)
 local n = select("#", ...)
 for i=1,n do
 t[format("%s%d",str,i)]=select(i,...)
 end
 for i=n+1, (t[str.."#"] or 0) do
 	t[format("%s%d",str,i)]=nil
 end
 t[str.."#"] = n
 end
__NOTOC__
Category:User defined functions