Metamethod when accessing a key as mutable - lua

__index is called when accessing as immutable :
local foo = bar["foo"];
__newindex is called when access as mutable an index that doesn't exist :
local bar = { }
bar["foo"] = 123 -- calls __newindex
bar["foo"] = 456 -- does NOT call __newindex
Is there a metamethod that can be called when accessing a key as mutable evey time, i.e not only if the key doesn't exist yet?
I would like to create a behavior so that when a users sets a key in a table, it calls a native method instead, regardless if the key already exists or not.

The standard way to do what you want is to use a proxy table, that is an empty table with suitable metamethods to access the actual table. Since the proxy is empty, the metamethods are called every time you get or set fields in it.

I am rather sure there are no such metamethods you ask for.
But you can try make a workaround to get what you want.
For example you can try to use the __call metamethod in this way:
local mt = {}
function mt.__call(tbl, key, val)
-- this is called every time you use bar(key, val)
tbl[key] = val
end
local bar = setmetatable({}, mt)
bar("foo", 123)
bar("foo", 456)
print(bar.foo)
Or you could use a function in some other way to achieve this.

Immutability doesn't exist in Lua, you just mean indexed accessing and assigning. Lua 5.3 states...
This event happens when table is not a table or when key is not
present in table.
...for both cases.
Your best option would be to store values in another table or subtable of yours.

Related

Pass Lua table by stringified reference instead of directly by reference

I want to pass a lua reference to another function without actually using assignment = but something like loadstring.
local myTable = { test="Hello" }
local myTableStringified = tostring(myTable) -- table: 0xref
print(myTableStringified)
local myTableUnstringified = loadstring(myTableStringified)
print(myTableUnstringified) -- nil but should show table: 0xref
As seen above, this won't do.
You'll have to use one of the modules that provide serialization.
Keep in mind that loadstring returns a function that needs to be called, so to get the table back you need to use loadstring(myTableStringified)().

Initialising and using a global table

I'm very new to Lua and I'm trying to globally initialise a table at the very start of my program. At the top, I have:
storage = {}
Then, I want to iterate over elements in this table inside functions in the same file. One example is:
local output
for item in storage do
output = output .. item
end
return output
In this case, I get:
attempt to call a nil value
On the line beginning with for.
I have also tried printing out storage[1]. In this case I get:
attempt to index local 'storage' (a nil value)
Could someone please explain in simple terms what could be wrong here?
You are not showing the entire script, but it's clear that storage value gets reset somewhere between your initialization and using in for item in storage do, because if it keeps the value, you'd get a different error: attempt to call a table value.
You need to use ipairs or pairs function in the loop -- for key, item in pairs(storage) do -- but you first need to fix whatever resets the value of storage.

Lua dont allow table append

I already have a lua-table A={}, A.B={} under global variable. I have a function on the call of what creates lua table D1={}, D1.D2={}, but the porblem is this function places the table in global variable list. When i print all lua values, it prints:
A={}, A.B={}, D1=={}, D1.D2={}. Is there a way I can create the function under table under A={}, A.B={} which mean i want output as:
A={}, A.B={}, A.B.D1=={}, A.B.D1.D2={}. I dont want to use table.insert() since the hirarchy of source-table is not known.
It sounds like what you want to do here, is pass the table to the function that creates D1 and D1.D2 so you can append those values wherever you want them.
function addTable(tbl)
tbl.D1 = {}
tbl.D1.D2 = {'test'}
end
addTable(A.B)
-- now you can call A.B.D1.D2
print(A.B.D1.D2[1]) -- prints 'test'

How do I add a method to the table type?

How do I add a method to the table type? I'm trying to write a method that searches through the values of a table. So far I have.
function table:contains(value)
for _, v in ipairs(self) do
if v == value then return true end
end
return false
end
Yet when I try to do the following.
t = {'four', 'five', 'six'}
t:contains('five')
I get the error.
stdin:1: attempt to call method 'contains' (a nil value)
Any suggestions?
As was said by others, your t is a simple table, it contains only the following key-value pairs: [1]='four', [2]='five', [3]='six'.
If you want to "extend" the t to be able to access functions from the table module, you have to set a metatable with __index pointing to the table module. I use the following function to access it easily:
function T(t)
return setmetatable(t, {__index = table})
end
You can then use it as follows (thanks to syntax sugar no parentheses needed):
t = T{'four', 'five', 'six'}
t:insert('seven')
print(t:contains('seven')) --> true
There is no single metatable for all tables. Unlike strings and numbers, each table has its own individual metatable.
Just make a free function instead of a "member" function for these kinds of things. Not everything needs to be all OOP with : and such.
You've added a method to the table library but you haven't given any metatable to table t. There is no automatic connection between table and t.

Can Lua support case-insensitive method calls?

I'm using Lua as a data description language for my C++ app. I have a bunch of C++ classes bound to Lua using SLB 2.0. I have methods bound such as 'SetPos' or 'SetName'. I specify the position or name (for example) using a table with values keyed as 'pos' or 'name'. I want to be able to take the key, prepend 'set', and call the method, if it exists (it may not). Is that possible? If so, any suggestions?
I know I could make my bound methods lower case, but I'd rather keep them the same as the methods they're bound to (that may be my fallback though). I could try to build the method name based on my naming standards, but case insensitivity is less error prone.
I feel there should be a tricky piece of Lua that could solve this using metatables, but I haven't been able to work it out myself.
Any suggestions?
Thanks!
Case insensitivity is not really something Lua handles. All table lookups and local variable accesses are ultimately case sensitive string compares.
The best solution would be to just accept that you're dealing with a case sensitive system, just like C++, and deal with it.
However, if you really want to, you can do this. The simplest way would be to put every possible case permutation of a name in your function table. So your function table would have this:
["setname"] = theFunction,
["Setname"] = theFunction,
["sEtname"] = theFunction,
["SEtname"] = theFunction,
...
You can of course automate this with a function that takes each name in the table and replicates its data based on the case permutations.
A more involved but easier to use mechanism would be to use the __index and __newindex metamethods along with the empty table trick.
function CreateCaseInsensitiveTable()
local metatbl = {}
function metatbl.__index(table, key)
if(type(key) == "string") then
key = key:lower()
end
return rawget(table, key)
end
function metatbl.__newindex(table, key, value)
if(type(key) == "string") then
key = key:lower()
end
rawset(table, key, value)
end
local ret = {}
setmetatable(ret, metatbl)
return ret
end
Instead of creating a table with {}, you create the table with this function call. The table should otherwise function as normal (though obviously member access will be slightly slower).

Resources