how to make then __index and __newindex detect table.index - indexing

I'm still a little newbie with metatables, and there is something that makes me confused
when I use metamethods like __index and __newindex in my metatable, they are only called when I invoke an element of the table as follows:
print(table[index]) -- this call the __index
table[index] = value -- this call the __newindex
but these two metamethods are not called when I invoke an element of the table as follows:
print(table.index) -- this does NOT call __index
table.index = value -- this does NOT call __newindex
my question is, is there any way to make table.index also call these two metamethods? or does only table[index] work?

Yes, __index will work with both brackets: mytable["index"] as well as the dot operator: mytable.index
mytable = setmetatable({}, { __index = function(t, k)
if k == "index" then
return "works fine"
end
return rawget(t, k)
end })
print(mytable["index"])
print(mytable.index)
You can circumvent the preset metatable methods using rawget and rawset
Having said that, if you are new to Lua I recommend looking for simple solutions that work WITHOUT metatables.

the __idnex and __newindex metamethods only get used when the table doesn't have an element at the index in question. If there's already an element, indexing will just return that element and setting it will just overwrite the existing element.
If you want complete control over all indices in a table, you have to keep it 100% empty and save all its values in another table and access those using the metamethods.

Related

Why Are My Tables Returning NIL and Not Populating?

I'm new to Lua and trying to understand the concept of OOP in Lua. To do so, I've tried creating an object and creating methods and "private variables". My issue is when I try to use "setters" or "getters", it's indicating that my tables are returning NIL which means I'm either having a scoping issue or something else I can't figure out.
The kicker is I'm using an example from an online Lua coding tutorial, and when I run the tutorial it works flawlessly. However, when I run mine, I get NIL or nothing outputs whenever I try to "get" or return a value from one of the member functions.
I'm using a couple of different environments:
ZeroBrain
Sublime Text
Lua for Windows
Do you know why my code is not returning populated tables?
newPlayer = function(n, h, a, r)
player = {}
n = n or ""
h = h or 100
a = a or 100
r = r or 0
function player:getPlayerName()
return n
end
function player:getPlayerHealth()
return h
end
function player:getPlayerArmor()
return a
end
function player:getPlayerRank()
return r
end
function player:setPlayerName(arg)
n = arg
end
function player:setPlayerHealth(arg)
h = arg
end
function player:setPlayerArmor(arg)
a = arg
end
function player:setPlayerRank(arg)
r = arg
end
function player:connect(arg)
print(string.format(" %s joined" , arg))
end
return player
end
player1 = newPlayer("John", 100, 100, 1000)
player1.getPlayerName()
Your code does not contain "populated tables" to return.
Your newPlayer function does create a table, and it does return it. It creates a number of functions within that table. But that's all newPlayer does: creates a table and puts some functions in it.
The data accessed by those functions is not part of the table. n, h, a, and r (BTW, please use better variable names) are all local variables. Your inner functions will access the specific stack containing those variables, but the variables themselves will not be magically associated with the table.
Your principle problem is almost certainly with the setters. And it comes from a combination of this:
function player:setPlayerName(arg)
with this:
player1.getPlayerName()
When you create a function using a : character between a table name and the function's name, you are using syntactic sugar for a function which implicitly takes as its first argument a value called self. As the name suggests, this is supposed to represent the object which this function is being called upon. So your function creation code is equivalent to:
function player.setPlayerName(self, arg)
Since you create all of your functions with :, all of your functions take at least one parameter.
The : syntax can also be used when calling such functions. If you did player1:getPlayerName(), this would cause the table you accessed to find the getPlayerName function to be used as the first argument in the function call. So that line would be equivalent to player1.getPlayerName(player1).
Obviously, these two syntaxes are mirrors of one another: functions created with : take a parameter that is expected to refer to the table it is being called on, and functions called with : will be given the table which was accessed to get that function.
But... your code didn't stick to the symmetry. You created the functions with :, but you call them with .
Now, you get functions are able to get away with this because... well, none of your values are actually part of the table. So your get functions just return the local value that they adopted from their creating context.
The set functions pose a problem. See, they take a parameter. But because the function was declared with :, they really take two parameters, the first being the implicit self.
Now, : syntax is just syntactic sugar; it's just a convenient way to do what you could have done yourself. So it is in theory OK to call a function with . even if you created it with :. But if you do so, you must pass the table as the first parameter. Though your code doesn't show it, I strongly suspect you didn't do that.
If you called player1.setPlayerName("foo"), what will happen is that the implicit self parameter will get the value "foo", and the arg parameter will be nil. And you will assign that nil value to the n local variable. So subsequent calls to player1.getPlayerName() will return nil.
Basically, what's going on here is that you're combining two different ways of creating objects in Lua. You stored your private data in a way that external code cannot access (ie: local upvalues), but that data is now no longer part of the table itself. Which means that, although you dutifully create those functions with : syntax to indicate that they take a self table, they never actually use that table. And because they never use the table, it's a lot harder to figure out what's going wrong.
Basically, the key here is to be symmetrical. If you create a function with :, then you should either call it with : or make sure to pass it the object table as the first parameter.
Broadly speaking, the standard way to create private members is by convention, not by forbidding it. That is, you agree not to mess with any members of a table other than those with certain names. Python convention is to pretend that names starting with _ don't exist, and Lua programs sometimes use that.
Upvalues are an interesting solution for private variables, but they do come with problems. If you want to invent a member variable, you have to do it in a centralized place rather than wherever you might need one. Even if the variable is optional, you have to create a named local at the top of the function.
TLDR of Nicol's answer, see my answer to another question:
function player:setPlayerArmor(arg)
a = arg
end
The : syntax is syntactic sugar. It creates an implicit 'self' argument when declared, and when used. If you declare it one way and use it another, the arguments won't be what you're expecting. Say your player has 100 health. Look at this result:
player1.setPlayerHealth(55, 66)
print(player1.getPlayerHealth())
-- will display '66', not '55' because `:` declares implicit 'self' argument
This displays 66 because the setPlayerHealth function has an implicit 'self' parameter because it was declared with :. If you instead called it
with the ::
player1:setPlayerHealth(55, 66)
print(player1:getPlayerHealth())
-- will display '55' because `:` passes player1 as self
function player:setHealth1(arg)
-- implicit 'self' argument refers to player1 when called on player1
end
-- is the same as
function player.setHealth2(self, arg)
-- with `.` notation, you need to add the 'self' argument explicitly
end
player1.setHealth1(31) -- self argument will be 31 and arg will be nil
player1.setHealth2(32) -- self argument will be 32 and arg will be nil
player1:setHealth1(33) -- self argument will be player1 and arg will be 33
player1:setHealth2(34) -- self argument will be player1 and arg will be 34

Inherit from table returned from function

There is an API provided function, let's call it createBase which returns a table (object). I want to add methods to this table, but I can't just do x = createBase() and then function x:foo() because I have another function similar to createBase, but it's createExtended. It might be easier to explain with the code I have so far:
import api --I don't know how you'd do this in vanilla Lua, I'd use os.loadAPI("api") but that's computercraft specific, I think
Extended = {}
function Extended:foo()
print("foo from extended")
end
function createExtended(params)
x = api.createBase(params)
Extended.__index = x
return Extended --this is obviously wrong: you can't return a class and expect it to be an object
end
Of course, this doesn't work: but I don't know how I might make it work either. Let's assume the table returned by createBase has a function called bar which just prints bar from base. With this test code, the following outputs are given:
e = createExtended()
e.foo() --prints "foo from extended"
e.bar() --nil, therefor error
How can I make this possible, short of defining function x.bar() inside createExtended?
Thanks in advance.
The very simplest way is to attach the method to it directly, instead of using a metatable.
local function extend(super_instance)
super_instance.newMethod = newMethod
return super_instance
end
local function createExtended(...)
return extend(createSuper(...))
end
This will work, unless your superclass uses __newindex (for example, preventing you from writing to unknown properties/methods), or iterates over the keys using pairs or next, since it will now have an additional key.
If for some reason you cannot modify the object, you will instead have to 'wrap' it up.
You could make a new instance which "proxies" all of its methods, properties, and operators to another instance, except that it adds additional fields and methods.
local function extend(super_instance)
local extended_instance = {newMethod = newMethod}
-- and also `__add`, `__mul`, etc as needed
return setmetatable(extended_instance, {__index = super_instance, __newindex = super_instance})
end
local function createExtended(...)
return extend(createSuper(...))
end
This will work for simple classes, but won't work for all uses:
Table iteration like pairs and next won't find the keys from the original table, since they're not actually there. If the superclass inspects the metatable of the object it is given (or if the superclass is actually a userdata), it will also not work, since you'll find the extension metatable instead.
However, many pure-Lua classes will not do those things, so this is still a fairly simple approach that will probably work for you.
You could also do something similar to Go; instead of having a way to 'extend' a class, you simply embed that class as a field and offer convenience to directly calling methods on the wrapping class that just call the methods on the 'extended' class.
This is slightly complicated by how 'methods' work in Lua. You can't tell if a property is a function-that-is-a-property or if it's actually a method. The code below assumes that all of the properties with type(v) == "function" are actually methods, which will usually be true, but may not actually be for your specific case.
In the worst case, you could just manually maintain the list of methods/properties you want to 'proxy', but depending on how many classes you need to proxy and how many properties they have, that could become unwieldy.
local function extend(super_instance)
return setmetatable({
newMethod = newMethod, -- also could be provided via a more complicated __index
}, {
__index = function(self, k)
-- Proxy everything but `newMethod` to `super_instance`.
local super_field = super_instance[k]
if type(super_field) == "function" then
-- Assume the access is for getting a method, since it's a function.
return function(self2, ...)
assert(self == self2) -- assume it's being called like a method
return super_field(super_instance, ...)
end
end
return super_field
end,
-- similar __newindex and __add, etc. if necessary
})
end
local function createExtended(...)
return extend(createSuper(...))
end

Deleting a table passed into a function, within the function

How can I set a table that I pass into a function to nil? When I try
local t = {}
function deleteTable(table)
table = nil
end
deleteTable(t)
Nothing happens, t still points to a table value. Is there any way to set the table passed into a function to nil from within the function?
Edit: Not trying to delete the contents of the table, what I wanted was to remove a reference to a table from within a function so that the table would be garbage collected. I misspoke out of ignorance of what I was actually trying to do.
Simply said, you cannot set a table to nil:
A table is a table is a table.
What you can do is setting the variable or slot of a table pointing to said table to something else like nil.
There is no way (outside the debug-api) to refer to local variables, and you would need table and key to refer to a slot in a table.
But even then the table is only garbage-collected if all such references are gone, and not immediately.
Lua does not do manual memory-management, but lazy garbage-collection.
I believe I found a solution. Would this work for what I'm trying to do?
local t = {};
function removeReference(tab)
--do stuff with tab
return nil;
end
t = removeReference(t);
In the above example I could just do t = nil and not use a function, but in my program the function does other things with the table first; I just want it to end in removing the reference. So is this the best solution, or is there a more ideal way?

Lua - How do I dynamically call a module?

Here's some much-simiplified Lua code I'm working with. I need to know how to dynamically call another module ('zebra'):
avar = require "avar"
bvar = require "bvar"
function create(zebra)
print(zebra.new())
end
print(create(avar))
And here are two modules:
local Avar = {}
function Avar.new()
return "avar"
end
return Avar
local Bvar = {}
function Bvar.new()
return "new"
end
function Bvar.old()
return "old"
end
return Bvar
If I try to pass in the string "avar" to my 'create' function, it doesn't work. If I pass in the word 'avar' with no quotes, it does work, however, I don't understand what avar with no quotes is? It seems to be a blank table? Not sure how to pass a blank table as an argument in my main program.
But maybe I'm totally on the wrong path. How do I dynamically call modules?
You can require any time:
function create(zebraModuleName)
zebraType = require(zebraModuleName)
print(zebraType .new())
end
print(create("avar"))
print(create("bvar"))
avar without the quotes is a global variable you created. It is initialized to the value returned by the require function1, which is the value returned by the module you are invoking. In this case, its a table with the new field that happens to be a function.
1 Importing a modules in Lua is done via regular functions instead of a special syntax. The function call parenthesis can be ommited because parens are optional if you write a function call with a single argument and that argument is a string or a table.
Other than that, there are also some other things you are confusing here:
The table you are storing on avar is not empty! You can print its contents by doing for k,v in pairs(avar) do print(k,v) end to see that.
The avar, bvar and create variables are global by default and will be seen by other modules. Most of the time you would rather make them local instead.
local avar = -- ...
local bvar = -- ...
local function create (zebra)
-- ...
end
The create function clearly expects a table since it does table indexing on its argument (getting the new key and calling it). The string doesn't have a "new" key so it won't work.
You aren't really dynamically calling a module. You are requiring that module in a regular way and it just happens that you pass the module return value into a function.
create always returns nil so there is no point in doing print(create(avar)). You probablu want to modify create to return its object instead of printing it.
You can use standard require from lua language or build your own loader using metatables/metamethods.
1. create a global function:
function dynrequire (module)
return setmetatable ({},{
__index = function (table,key)
return require(module..'.'..key)
end
})
end
2. Create your project tree visible to package.path
./MySwiss/
\___ init.lua
\___ cut.lua
\___ glue.lua
\___ dosomething.lua
3. Make your module dynamic
you only need to put this line on your MySwiss/init.lua (as if you were namespacing a PHP class):
return dynrequire('MySwiss')
4. Require your module and use subproperties dynamically
On your script you only need to require MySwiss, and the folder file (or subfolders with dynrequire('MySwiss.SubFolderName').
var X = require('MySwiss')
X.glue()
Note that MySwiss doesn't have glue key. But when you try access de glue key the metamethod __index try to require submodule. You can the full project tree using this technique. The only downside is the external dependencies not packed this way.

Is there some clever way to write a lua object so that it doubles up as an iterator?

Lets say I have some "object" that I've defined elsewhere. Maybe it represents a set of items, but is more complex than a simple table. Whatever it may be, it would be logical to iterate over it.
As such, it has a iterator method defined. So I can write this:
local myObject = AbstractObject:new()
for obj in myObject:iterator() do
obj:foo()
end
What I'm wondering is if there is some metamethod trickery that I can do, which will allow me to write this:
local myObject = AbstractObject:new()
for obj in myObject do
obj:foo()
end
So is there?
One slight change to your example would make the semantics a lot less painful:
local myObject = AbstractObject:new()
for obj in myObject() do
obj:foo()
end
That way, you can use a metatable to define the __call metamethod to return myObject:interator(), with code that looks something like this in AbstractObject:new():
setmetatable(newobject, {__call = function() return newobject:iterator() end})
Without the iterator construction, you'll be effectively reusing a single iterator for multiple iterations, which means you'll need to keep the iterator state in the object/creation closure, and reset it after it finishes so the next call will restart the iteration again. If you really want to do this, the best solution would really be to write something for the specific iteration implementation, but this would perform the generic iteration:
local iterator
--table.pack is planned for 5.2
local pack = table.pack or function(...)
local t = {...}
t.n = select('#',...)
return t
end
--in 5.1 unpack isn't in table
local unpack = table.unpack or unpack
function metamethods.__call(...)
if not iterator then
iterator = newobject:iterator()
end
local returns = pack(iterator(...))
if returns[1] == nil then
--iteration is finished: next call will restart iteration
iterator = nil
end
return unpack(returns, 1, returns.n)
end
Again: This should really be adjusted to fit your use case.
The object used after in must be a function, which will be called repeatedly by the generic for loop.
I'm not sure if you can make a table or user object callable like a function, but even then the problem would be that your object can only have one internal iterator state - i.e. it would not allow multiple iterations over the same object (neither concurrently nor sequentially), unless you are somehow explicitly resetting it.
As answered by Stuart, you could use the __call metamethod suitably to return the iterator, but then you would have to write
for obj in myObject() do
obj:foo()
end
This is not quite what we want.
Reading a bit more in PiL, I see that there are more components used in the for loop: the invariant loop state, and the current value of the control variable, which are passed to the iterator function in each call. If we don't provide them in the in expression, they are initialized to nil.
Thus, my idea would be to use these values to distinguish the individual calls.
If you can create a next(element) function for your collection which returns for each element the next one, the implementation would be simple:
metatable.__call = function(_state, _last)
if(_last == nil) then
return obj:first()
else
return obj:next(_last)
end
end
But often we would not have something like this, then it gets more complicated.
I thought about using coroutines here, but these still need a factory method (which we want to avoid).
It would result in something similar like what Stuart wrote (i.e. saving the iterator state somewhere in the object itself or in some other variable related to the object), and using the parameter and/or the iterators result to decide when to create/clean the iterator object/state.
Nothing won here.