I have used Python, but now I'm learning Lua because of Torch. The word 'metatable' is really hard to understand for me. For example, is metatable a special kind of table? How does it change the behavior of table?
A metatable is simply a table that is used to control the behavior of another table (or userdata, or other Lua value). A table is a metatable only because it is used as a metatable. That is, being a "metatable" is not a fundamental property of a table. There is no "create_metatable" function or anything. It's just the name we use for a table which is used to control other tables.
Certain operations on tables (or userdata) are specified to check the table's metatable first. If the table (or userdata) has a metatable, and that metatable has a certain key/value pair in it, then the operation will use that key/value pair to perform that operation instead of the normal logic.
Each operation which can be overridden by a metatable has a specific key name associated with it. So if you try to perform addition on a table, the system will look for the __add key in the metatable in order to access it.
The value in the pair is usually (though not always) a function. Such functions are generally called "metafunctions". The parameters it takes and the meaning of its return value is defined by the particular operation calling it. A few operations allow the value to be a table or something else.
In Lua, you assign a metatable to a table (but not userdata) with the setmetatable function. From C, you use the lua_setmetatable function to assign a table (or userdata) a metatable.
Metatables are particularly important for C code that exposes C objects as userdata. Raw userdata is just an opaque blob of bits; Lua defines very few legal operations that can be performed on them by default. But by assigning them a metatable, you can give the userdata more abilities through metafunctions.
Note that Lua values other than tables and userdata can have metatables. However, unlike tables and userdata, values of each Lua type all share the same metatable for that type. So all strings have the same metatable, all numbers have the same metatable, etc.
Hello
After a while of reading and understanding what a metatable could be i like to post a working example. So everybody can see and feel how usefull it can be. The example change the # operator for the associated table. Because i realized # counts only correct not named keys. # ignores also 0 and negative numbers. And here is the working example how to replace it with a function that counts every table correct...
# lua
Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
> -- Defining a table with 3 key/value pairs
> my_table={[0]=0,[1]=1,['metatable']={}}
> #my_table
1
> -- # is counting wrong it counts only my_table[1]
> -- Now set the empty my_table.metatable to my_table
> setmetatable(my_table,my_table.metatable)
> -- So it can be accessed without getmetatable()
> -- Now replacing # for associated table my_table
> -- in my_table.metatable with the metafuncion __len
> my_table.metatable.__len=function(array) local incr=0 for _ in pairs(array) do incr=incr+1 end return incr end
> -- Let's test # ...
> #my_table
3
> -- Now # is usefull because it counts correct
> -- And my_table.metatable can be set as a metatable for other tables
> -- where # is counting wrong but needed to count the correct way
> #_G
0
> setmetatable(_G,my_table.metatable)
> #_G
45
> #package.loaded
0
> setmetatable(package.loaded,my_table.metatable)
> #package.loaded
12
> -- Like _G or package.loaded for example
Related
Our task is create a table, and read values to the table using a loop. Print the values after the process is complete. - Create a table. - Read the number of values to be read to the table. - Read the values to the table using a loop. - Print the values in the table using another loop. for this we had written code as
local table = {}
for value in ipairs(table) do
io.read()
end
for value in ipairs(table) do
print(value)
end
not sure where we went wrong please help us. Our exception is
Input (stdin)
3
11
22
abc
Your Output (stdout)
~ no output ~
Expected Output
11
22
abc
Correct Code is
local table1 = {}
local x = io.read()
for line in io.lines() do
table.insert(table1, line)
end
for K, value in ipairs(table1) do
print(value)
end
Let's walk through this step-by-step.
Create a table.
Though the syntax is correct, table is a reserved pre-defined global name in Lua, and thus cannot should not be declared a variable name to avoid future issues. Instead, you'll need to want to use a different name. If you're insistent on using the word table, you'll have to distinguish it from the function global table. The easiest way to do this is change it to Table, as Lua is a case-sensitive language. Therefore, your table creation should look something like:
local Table = {}
Read values to the table using a loop.
Though Table is now established as a table, your for loop is only iterating through an empty table. It seems your goal is to iterate through the io.read() instead. But io.read() is probably not what you want here, though you can utilize a repeat loop if you wish to use io.read() via table.insert. However, repeat requires a condition that must be met for it to terminate, such as the length of the table reaching a certain amount (in your example, it would be until (#Table == 4)). Since this is a task you are given, I will not provide an example, but allow you to research this method and use it to your advantage.
Print the values after the process is complete.
You are on the right track with your printing loop. However, it must be noted that iterating through a table always returns two results, an index and a value. In your code, you would only return the index number, so your output would simply return:
1
2
3
4
If you are wanting the actual values, you'll need a placeholder for the index. Oftentimes, the placeholder for an unneeded variable in Lua is the underscore (_). Modify your for loop to account for the index, and you should be set.
Try modifying your code with the suggestions I've given and see if you can figure out how to achieve your end result.
Edited:
Thanks, Piglet, for corrections on the insight! I'd forgotten table itself wasn't a function, and wasn't reserved, but still bad form to use it as a variable name whether local or global. At least, it's how I was taught, but your comment is correct!
The index metamethod can be set equal to tables. From what I can tell
foo.__index = function(self, k)
return bar[k]
end
and
foo.__index = bar
are the same. Why is declaring functions this way allowed in this situation?
This isn't a function declaration - assigning a table to __index is just a shortcut for using the function that you described.
From Programming in Lua (for Lua 5.0, but this part of the language hasn't changed):
The use of the __index metamethod for inheritance is so common that
Lua provides a shortcut. Despite the name, the __index metamethod does
not need to be a function: It can be a table, instead. When it is a
function, Lua calls it with the table and the absent key as its
arguments. When it is a table, Lua redoes the access in that table.
It's not like the table that you assign magically becomes a function. type(foo.__index) will still return table, and you can still do things with it that you can do with other tables, like using pairs and next, etc.
Rawset function in lua generally is passed table, index and value but I came across this code:
rawset(tbl,name,{})
and
rawset(tbl,name, function() end)
Rawset function returns a table, so what does it mean to have a table or function in rawset function in place for value ?
Lua tables can hold values of all types, including tables and functions, and they can be heterogeneous: not all values need to be of the same type.
See http://www.lua.org/manual/5.2/manual.html#2.1.
From reference manual:
rawset (table, index, value): Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, index any value different from nil, and value any Lua value.
What this means:
table's metatable is not used: that's why it is "raw" set, the field is added directly; without raw, the table's metatable will be used to handle the "set" action;
index any value different from nil: in Lua, this really means any type of Lua object other than nil: a number, a function, another table, etc (Lua ref manual lists all types);
value any Lua value: same as previous, but can even be nil: if set to nil, effectively removes item from table.
So index being name just indicates the table is an associative array (unless name is a number but that would be misleading), in first case the associated value is another table, in the second case it is a Lua function.
__index = function(tbl, key)
local a = tbl[key]
if a <=0 then a = 0 end
if a > 5 then a = 0 end
return a
end
Book says:
Though the preceding code looks very innocent and tries to keep the value of the element in the table within a range, this code will cause problems and circular references. The first line in the function, a = tbl[key], will actually trigger another index function call, and that in turn will invoke another, and so on.
But how is a = tbl[key] calling another index at every call ?
That is a bit wierd thing to do. Lua triggers __index metamethod only if it can't find a field in the table. Therefore, using tbl[key] inside it makes absolutely no sense at all. Unless tbl is not a table.
Anyhow, if you want to access a table's field from within __index, use rawget. That will ensure that no metamethods are called.
EDIT:
Let me explain how __index lookup works:
Let's assume the table has a metatable with __index defined.
If Lua can't find the key in the table, it looks for the __index field in the metatable. It does not look for the key itself. Then, if the __index is a table, it looks for the key in that table (not the metatable, although it is common to associate the metatable itself with its __index field). If it is a function, it is invoked with two parameters: table (initial table, not the metatable) and the key.
So if the __index metamethod is called, you can be certain that the initial table does not have that field defined. Therefore, when you try to index it again (as the first argument is the original table that triggered the index lookup), the story begins anew -> Lua can't find the key, it invokes the __index and so on.
I made an interactive command shell which is operating by Lua interpreter. User input some command, shell calls something like lua_dostring to execute it. I want to allow users to define their own functions in arbitrary table, and save it to separated storage (like a file) automatically. According to the manual, I can get exact source code input by user with lua_Debug.
It looks possible to save the functions sources to some files after all execution done. But I want to save automatically when it's just added/remove.
Can I detect the moment of some value is just added to a table?
Yes. If you have a table tbl, every time this happens:
tbl[key] = value
The metamethod __newindex on tbls metatable is called. So what you need to do is give tbl a metatable and set it's __newindex metamethod to catch the input. Something like this:
local captureMeta = {}
function captureMeta.__newindex(table, key, value)
rawset(table, key, value)
--do what you need to with "value"
end
setmetatable(tbl, captureMeta);
You will have to find a way to set the metatable on the tables of interest, of course.
Here's another way to do this with metatables:
t={}
t_save={}
function table_newinsert(table, key, value)
io.write("Setting ", key, " = ", value, "\n")
t_save[key]=value
end
setmetatable(t, {__newindex=table_newinsert, __index=t_save})
Here's the result:
> t[1]="hello world"
Setting 1 = hello world
> print(t[1])
hello world
Note that I'm using a second table as the index to hold the values, instead of rawset, since __newindex only works on new inserts. The __index allows you to get these values back out from the t_save table.