Can LUA meta tables assist in detection of nilling object? - lua

I was wondering if you can detect the nilling of an object through meta tables ?
foo = {}
foo_mt = {
__newindex = function (t, k, v)
print (k, v)
rawset (t, k, v)
end
}
setmetatable (foo, foo_mt)
foo ['oof'] = 3
outputs: oof 3
foo ['oof'] = nil
__newindex will not be called, so is there another meltable method ?

Just to clarify, __newindex is only triggered when the previous value is nil. So the following code will trigger __newindex twice:
foo = {}
foo_mt = {
__newindex = function (t, k, v)
print (k, v)
rawset (t, k, v)
end
}
setmetatable (foo, foo_mt)
foo['oof'] = nil
foo['oof'] = nil
If foo['oof'] already has a non-nil value then __newindex will not be called (because the index already exists).
But yea, you need something like an empty proxy table if you want to catch all modifications to your table like Egor pointed out.
proxy = {}
foo = {}
foo_mt = {
__newindex = function (t, k, v)
print (k, v)
rawset (proxy, k, v)
end,
__index = function(t, k)
return rawget(proxy, k)
end
}
setmetatable (foo, foo_mt)
foo['ok'] = true
foo['ok'] = nil

Related

ROBLOX LUA(u) check arguments of a function

I have this function.
As you can see, I define fn to run a function with arguments provided, how can I check if the amount of arguments that the fn function receives is the amount needed for the function v? Ie, if the user provides 2 args but 3 are needed, throw an error.
ModuleScript:
-- Variables
local dss = game:GetService("DataStoreService")
local db = dss:GetDataStore("greenwich")
-- Tables
local greenwich = {}
local dbFunctions = {}
-- Functions
function greenwich:GetDB(name)
local new = {}
new.name = name
coroutine.resume(coroutine.create(function()
for k, v in pairs(dbFunctions) do
local fn = function(...)
local args = {...}
return v(unpack(new), unpack(args))
end
new[k] = fn
new[string.lower(k)] = fn
end
end))
return new
end
function dbFunctions:Set(store, key, value)
store = store.name
db:SetAsync(store .. key, value)
return value
end
function dbFunctions:Get(store, key)
store = store.name
return db:GetAsync(store .. key)
end
function dbFunctions:Delete(store, key)
store = store.name
local success, val = pcall(function()
return db:RemoveAsync(store .. key)
end)
if val and success then
return true
else
return false
end
end
function dbFunctions:Has(store, key)
store = store.name
return not not db:GetAsync(store .. key)
end
-- Returning everything.
return greenwich
In the standard library of Lua 5.3.5, you can use the debug.getInfo() function to inspect the function. The table that is returned contains a field called nparams which will tell you how many args the function expects.
local example = {}
function example.func(a, b, c)
print(a, b, c)
end
local info = debug.getinfo(example.func)
print(info.nparams) -- 3
In Roblox Lua, which is a custom version based on Lua 5.1, the debug library is heavily modified and you'll need to use the debug.info() function. When you pass in a function and the argument "a", it returns the arity of the function.
local example = {}
function example.funcA(a, b, c)
print(a, b, c)
end
function example:funcB(a, b, c)
print(a, b, c)
end
function example:funcC(a, b, c, ...)
print(a, b, c)
end
-- print out the number of args and whether there's a vararg
print(debug.info(example.funcA, "a")) -- 3 false
print(debug.info(example.funcB, "a")) -- 4 false
print(debug.info(example.funcC, "a")) -- 4 true

(lua) What is the role of the parameter t in this search function?

The following code is a multi-inheritance demo in Programming in Lua.
local function search(k, plist)
for i=1, #plist do
local v = plist[i][k]
if v then return v end
end
end
function createClass(...)
local c = {}
local parents = {...}
-- what's the role of parameter t?
setmetatable(c, {__index = function (t, k)
return search(k, parents)
end})
c.__index = c
function c:new(o)
o = o or {}
setmetatable(o, c)
return o
end
return c
end
Account = {
balance = 0,
withdraw = function (self, v) self.balance = self.balance - v end,
deposit =function (self, v) self.balance = self.balance + v end,
getbalance = function (self) return self.balance end,
new = function (self, v)
v = v or {}
setmetatable(v, self)
self.__index = self
return v
end,
}
Named = {
name = "",
getname = function (self) return self.name end,
setname = function (self, n) self.name = n end,
}
NamedAccount = createClass(Account, Named)
account = NamedAccount:new{name = 'Paul'}
print(account:getname())
account:setname("Phoenix")
print(account:getname())
account:deposit(1000)
print(account:getbalance())
account:withdraw(221)
print(account:getbalance())
As is shown in the code above, what is the role of parameter t in the statement setmetatable(c, {__index = function (t, k) return search(k, parents) end}). The parameter t doesn't seem to be used. I've tried to delete it, but I got a error message:
lua: Multi-inheritance.lua:46: attempt to call a nil value (method 'getname')
stack traceback:
Multi-inheritance.lua:46: in main chunk
[C]: in ?
It looks as if I cannot delete it simply. Is there anyone can tell me what the role of t plays here?

Lua OOP. How to inherit tables from a prototype

In Programming in Lua I found an example to work with inheritance. I understood how it is handled through metatable __index but when I made my own example where one of the items to inherit is a table I realised the table is shared by new created objects:
Account = {
balance = 0,
info = {},
withdraw = function (self, v)
self.balance = self.balance - v
end,
deposit = function (self, v)
self.balance = self.balance + v
end,
add = function (self, item)
if self:check(item) then return end
table.insert(self.info, item)
end,
remove = function (self, item)
table.remove(self.info, item)
end,
check = function (self, item)
for i, v in ipairs(self.info) do
if v == item then return true end
end
end,
new = function (self, o)
o = o or {}
self.__index = self
setmetatable(o, self)
return o
end,
}
local a1 = Account:new()
local a2 = Account:new()
local a3 = Account:new()
a1:deposit(50)
a1:add("aaa")
a2:deposit(100)
a2:add("bbb")
a2:add("bbb")
print(a1.balance)
for _, v in ipairs(a1.info) do print(v) end
print(a2.balance)
for _, v in ipairs(a2.info) do print(v) end
Here info is shared by all objects:
50
aaa
bbb
100
aaa
bbb
How can I make info unique in each new objects?
EDIT. The workaround is I put all "fields" to the method new whilst left methods in a prototype but I don't see it is very elegant:
new = function (self, o)
o = o or {}
o.balance = 0
o.info = {}
self.__index = self
setmetatable(o, self)
return o
end,
Thanks
The answer might be easier than you think; you assign info in the "class" table. Instead, just assign a new info table to every instance in the constructor:
function Account:new(instance)
instance = instance or {}
instance.info = {}
setmetatable(instance, self)
return instance
end
Note that, in my example, I've removed the line self.__index = self because you shouldn't be doing that in the constructor. Instead, assign it once after you've created the table as Account.__index=Account

Lua - implement userdata iterator

Lua 5.2
I need to iterate an userdata variable.
As I understand, I can do this using getmetatable and __pairs. Like this:
for k, v in getmetatable(userdataVariable).__pairs do
-- someting
end
But I get 'attempt to call a nil value' when I'm trying to do this.
I found a __pairs implementation here: what is actual implementation of lua __pairs?
function meta.__pairs(t)
return function(t, k)
local v
repeat
k, v = next(t, k)
until k == nil or theseok(t, k, v)
return k, v
end, t, nil
end
But I don't understand what I should do with theseok? What function should I define here?
I think you're looking for the __index meta table.

what is actual implementation of lua __pairs?

Does anybody know actual implementation of lua 5.2. metamethod __pairs? In other words, how do I implement __pairs as a metamethod in a metatable so that it works exactly same with pairs()?
I need to override __pairs and want to skip some dummy variables that I add in a table.
The following would use the metatable meta to explicitly provide pairs default behavior:
function meta.__pairs(t)
return next, t, nil
end
Now, for skipping specific elements, we must replace the returned next:
function meta.__pairs(t)
return function(t, k)
local v
repeat
k, v = next(t, k)
until k == nil or theseok(t, k, v)
return k, v
end, t, nil
end
For reference: Lua 5.2 manual, pairs
The code below skips some entries. Adapt as needed.
local m={
January=31, February=28, March=31, April=30, May=31, June=30,
July=31, August=31, September=30, October=31, November=30, December=31,
}
setmetatable(m,{__pairs=
function (t)
local k=nil
return
function ()
local v
repeat k,v=next(t,k) until v==31 or k==nil
return k,v
end
end})
for k,v in pairs(m) do print(k,v) end

Resources