This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Konlab's profile picture

Delegates in Lua (metatable trick)

Started by Konlab, 08 November 2015 - 06:27 PM
Konlab #1
Posted 08 November 2015 - 07:27 PM
Delegates in Lua
Basically, it's a container for functions
You can add functions to it, remove functions from it, call it.

If you don't know what delegates are check out this page: https://msdn.microso...y/ms173171.aspx
Changelog: (dd-mm-yyyy)
09.11.2015: added events
10.11.2015: Changed how things are added & removed from delegate
SpoilerOld:
 a = delegate()
b = function() print("b") end
a = a + b 
New:
 a = delegate()
b = function() print("b") end
--# now has no return value, changes the table
a + b 
--# or you can now also do:
a:add(B)/>
Same for removing, a - b or a:sub(B)/>
You can get an event from delegate by calling:
e = event(d) (where d is your delegate)
The generated event will only have 2 methods (not meta): add(func) and sub(func), which is good for security reasons. If you modify the generated event, the original delegate will be modified, too (pointer magic).

Get it here:
http://pastebin.com/Rgnrgaxh
 pastebin get Rgnrgaxh delegate 

How to use it?
When loaded with os.loadAPI("delegate"), you can do:
a = delegate.delegate() --# if loaded with dofile() or shell.run() you can simply do delegate()

--# when b is our function we want to add simply (must be in THIS order or errors will happen):
a + b
--# or you can also do simply:
a:add(B)/>
--# we added b to our delegate
--# to remove it (this removes ALL of b-s from a)  (must be in THIS order or errors will happen):
a - b
--# or you can do simply:
a:sub(B)/>

--# to call the delegate simply
count,returnvals = a()
--# count is the total number of functions ran and returnvals is a table of return vals by pcall:
--# {{(boolean),(error msg),(other returned values)}}
--# you can also call it with params, all function in the delegate will receive the params:
count,returnvals = a("im a param")

--#Yes all of the functions in it are pcalled, but the metatable will throw errors if used incorrectly:
a + 2 --#will error, because you can't add numbers and delegates
a - 2 --# will error too

--# You can access all functions in it with the func index:
functionCount = #a.func --will be the count of functions

--#And last thing: resetting
--#You have to do:
a = delegate()

Events usage:
--# if you loaded it with os.loadAPI you have to put the filename prefix before delegate() and event()
local d = delegate()
--# a is your function you want to add to the delegate, but you don't want to make d global, you only want to let programs subscribe and unsubscribe
--# to do this you will make a public event from d
e = event(d)
--# you can't call events, you have to call its delegate
d()
--# now in other program you can subscribe and unsubscribe but you can't damage the delegate
e.add(a)
e() --# error attempt to call table
e = nil --# will leave delegate undamaged
e.sub(a) --# will unsubscribe a from the delegate
Why is this useful?
I made this for my multitasking, so programs can subscribe their functions for events instead of being continued with a custom event message.

Please post your opinion, ideas, suggestions etc. below!
Edited on 10 November 2015 - 05:58 PM
Konlab #2
Posted 09 November 2015 - 05:06 PM
I am thinking of implementing events, or something for security like that events added ( https://msdn.microso...a645739(v=vs.71).aspx )
Also here are some more non-C# tutorials (useful, if you are not familiar with C#)
I couldn't found a non-C# example, sorry :(/>/>

https://en.wikipedia...gates_.28C.23.2

Edit: fixed links, Forums don't like links with characters ) and #
Edited on 09 November 2015 - 06:05 PM
Creator #3
Posted 10 November 2015 - 05:38 AM
Well this certainly is a nice trick, what would be some practical usage in a program/OS?
Konlab #4
Posted 10 November 2015 - 02:40 PM
Well this certainly is a nice trick, what would be some practical usage in a program/OS?
I use it in my multitasking for distributing events generated by the multitasking (e.g. id 1 ended) because I don't want to constantly continue every thread with things that they probably won't use. I publish an event delegate for every possible multitasking event. Then I have delegates like OnEnd and OnLaunch etc.
Konlab #5
Posted 10 November 2015 - 07:01 PM
Updated with new function adding
Events usage screenshot:



Edit:
d's code is:

function()
    print("d inited")
    print(os.pullEvent())
end
Edited on 10 November 2015 - 06:02 PM