implementing torch's __len__ meta function - lua

In our torch-dataframe project we're trying to implement __len__ meta function as follows :
MyClass.__len__ = argcheck{
{name="self", type="MyClass"},
{name="other", type="MyClass"},
call=function(self, other)
return self.n_rows
end}
This works in Lua 5.2 and 5.3 but for Lua 5.1, luajit 2.0 and 2.1 the returned variable is not the actual row number but 0. The sense is that it returns a new instance of MyClass but it's hard to understand why. There is a note about __len changing here but that's the best doc hint we've managed to locate so far.
A little surprising is the need for two arguments. When argcheck is provided with a single argument version:
MyClass.__len__ = argcheck{
{name = "self", type = "MyClass"},
call=function(self)
return self.n_rows
end}
it throws:
[string "argcheck"]:28:
Arguments:
({
self = MyClass --
})
Got: MyClass, MyClass
We currently rely on the argcheck overload operator for handling this:
MyClass.__len__ = argcheck{
{name="self", type="MyClass"},
{name="other", type="MyClass"},
call=function(self, other)
return self.n_rows
end}
MyClass.__len__ = argcheck{
overload=MyClass.__len__,
{name="self", type="MyClass"},
call=function(self)
return self.n_rows
end}
For more details here is the full class and the travis report :
Full metatable class
Travis report
Test case
Here's a full test-case that works as expected in 5.2 and 5.3 that perhaps illustrates the problem in a more concise way that the full package:
require 'torch'
local argcheck = require "argcheck"
local MyClass = torch.class("MyClass")
function MyClass:init()
self.n_rows = 0
end
MyClass.__len__ = argcheck{
{name = "self", type = "MyClass"},
{name = "other", type = "MyClass"},
call=function(self, other)
print(self.n_rows)
print(other.n_rows)
return(self.n_rows)
end}
local obj = MyClass.new()
obj.n_rows = 1
local n = #obj
print(n)
This prints as expected:
1
1
1

The issue is related to this SO question. There simply is no support for it in 5.1:
__len on tables is scheduled to be supported in 5.2. See LuaFiveTwo.

Related

Lua: Workaround for boolean conversion of a class variable when enclosed in parentheses

In the below code, can anyone explain why does t1:print() works but (t1):print fails. I am attempting to make something like (t1 * 3):print() work without using an intermediate variable.
function classTestTable(members)
members = members or {}
local mt = {
__metatable = members;
__index = members;
}
function mt.print(self)
print("something")
end
return mt
end
TestTable = {}
TestTable_mt = ClassTestTable(TestTable)
function TestTable:new()
return setmetatable({targ1 = 1}, TestTable_mt )
end
TestTable t1 = TestTable:new()
t1:print() -- works fine.
(t1):print() -- fails with error "attempt to call a boolean value"
Lua expressions can extend over multiple lines.
print
(3)
Will print 3
So
t1:print()
(t1):print()
actually is equivalent to
t1:print()(t1):print()
or
local a = t1:print()
local b = a(t1)
b:print()
So you're calling the return value of t1:print()
To avoid that follow Egors advice and separate both statements with a semicolon.
t1:print();(t1):print()

attempt to call method 'func' (a nil value)

No matter how I approach Lua, I run into this error all the time, so I must not understand something inherit to the language:
attempt to call method 'func' (a nil value)
I've seen the error here a few times as well but the problem doesn't seem clear to me.
Here's my module:
actor.lua
Actor = {
x = 0,
mt = {},
new = function()
local new_actor = {}
new_actor.x = Actor.x
new_actor.mt = Actor.mt
return new_actor
end,
test = function(self, a, b)
print(a, b)
end
}
I'm using Löve.
main.lua
require "game/actor"
local a = Actor:new() --works fine
function love.load()
a.x = 10
print(a.x) --output: 10
a:test(11, 12) --error: attempt to call method 'test' (a nil value)
end
I'm also not sure when it's appropriate to use the previous styling over this in a module.
Actor = {
x = 0
}
Actor.mt = {}
function Actor.new()
print(42)
end
I'm honestly not sure what is more correct than the other but considering I run into a simple error either way, there's probably something I'm missing entirely?
It looks like you're trying to instance a kind of class made of metatables. You basically need to assign new_actor's metatable with Actor.mt. (Resuming the problem: when you're indexing new_actor you're not indexing Actor in this case)
setmetatable(new_actor, Actor.mt);
Even if the metatable is being added, it won't work until you put the meta "__index" event to index a table containing your class methods/values, in this case:
Actor.mt = {
__index = Actor
};
I'd suggest moving your class methods/values into a new table, like Actor.prototype, Actor.fn, etc... avoiding conflicts:
Actor.fn = {
test = function(self, a, b)
print(a, b)
end
};
Actor.mt = {
__index = Actor.fn
};
More about metatables in Lua 5.3 manual.

Simple LZW Compression doesnt work

I wrote simple class to compress data. Here it is:
LZWCompressor = {}
function LZWCompressor.new()
local self = {}
self.mDictionary = {}
self.mDictionaryLen = 0
-- ...
self.Encode = function(sInput)
self:InitDictionary(true)
local s = ""
local ch = ""
local len = string.len(sInput)
local result = {}
local dic = self.mDictionary
local temp = 0
for i = 1, len do
ch = string.sub(sInput, i, i)
temp = s..ch
if dic[temp] then
s = temp
else
result[#result + 1] = dic[s]
self.mDictionaryLen = self.mDictionaryLen + 1
dic[temp] = self.mDictionaryLen
s = ch
end
end
result[#result + 1] = dic[s]
return result
end
-- ...
return self
end
And i run it by:
local compressor = LZWCompression.new()
local encodedData = compressor:Encode("I like LZW, but it doesnt want to compress this text.")
print("Input length:",string.len(originalString))
print("Output length:",#encodedData)
local decodedString = compressor:Decode(encodedData)
print(decodedString)
print(originalString == decodedString)
But when i finally run it by lua, it shows that interpreter expected string, not Table. That was strange thing, because I pass argument of type string. To test Lua's logs, i wrote at beggining of function:
print(typeof(sInput))
I got output "Table" and lua's error. So how to fix it? Why lua displays that string (That i have passed) is a table? I use Lua 5.3.
Issue is in definition of method Encode(), and most likely Decode() has same problem.
You create Encode() method using dot syntax: self.Encode = function(sInput),
but then you're calling it with colon syntax: compressor:Encode(data)
When you call Encode() with colon syntax, its first implicit argument will be compressor itself (table from your error), not the data.
To fix it, declare Encode() method with colon syntax: function self:Encode(sInput), or add 'self' as first argument explicitly self.Encode = function(self, sInput)
The code you provided should not run at all.
You define function LZWCompressor.new() but call CLZWCompression.new()
Inside Encode you call self:InitDictionary(true) which has not been defined.
Maybe you did not paste all relevant code here.
The reason for the error you get though is that you call compressor:Encode(sInput) which is equivalent to compressor.Encode(self, sInput). (syntactic sugar) As function parameters are not passed by name but by their position sInput inside Encode is now compressor, not your string.
Your first argument (which happens to be self, a table) is then passed to string.len which expects a string.
So you acutally call string.len(compressor) which of course results in an error.
Please make sure you know how to call and define functions and how to use self properly!

Can I extract stack values from a parent function in Lua?

My game engine pushes a value on to the lua stack as a parameter to a function and then invokes it using lua_pcall. The lua code will run and call additional lua functions. Eventually this lua code will invoke a C function. Is it possible for this function to retrieve the value that was originally pushed on to the stack?
Its like this:
<engine function A>
pushes parameter value X on to stack for lua
<lua func>
<lua func>
<lua func>
<engine function B>
can I extract the values X that was pushed by function A here?
Yes, with a combination of getinfo, getlocal and getupvalue you can get all that information (you can even change those values using set* functions).
Here is a fragment from MobDebug that returns stack information along with a table of locals and upvalues at each level. The variables at each level will be indexed in the same order they appear in the code (starting from parameters). For each get* function you can use their C equivalents (lua_getinfo, lua_getlocal, and lua_getupvalue), but the logic should be exactly the same.
local function stack(start)
local function vars(f)
local func = debug.getinfo(f, "f").func
local i = 1
local locals = {}
while true do
local name, value = debug.getlocal(f, i)
if not name then break end
if string.sub(name, 1, 1) ~= '(' then locals[name] = {value, tostring(value)} end
i = i + 1
end
i = 1
local ups = {}
while func and true do -- check for func as it may be nil for tail calls
local name, value = debug.getupvalue(func, i)
if not name then break end
ups[name] = {value, tostring(value)}
i = i + 1
end
return locals, ups
end
local stack = {}
for i = (start or 0), 100 do
local source = debug.getinfo(i, "Snl")
if not source then break end
table.insert(stack, {
{source.name, source.source, source.linedefined,
source.currentline, source.what, source.namewhat, source.short_src},
vars(i+1)})
if source.what == 'main' then break end
end
return stack
end

Storing values in a userdata object from lua

What I want to do is this:
object.foo = "bar"
print(object.foo)
where "object" is a userdata.
I've been googling for a while (using the keyword __newindex and lua_rawset) but I can't any examples that do what I want it to do.
I want to do this in with the lua api in c++
Let us write this in Lua code so that we can make quick experiments with the code
function create_object()
-- ## Create new userdatum with a metatable
local obj = newproxy(true)
local store = {}
getmetatable(obj).__index = store
getmetatable(obj).__newindex = store
return obj
end
ud = create_object()
ud.a = 10
print(ud.a)
-- prints '10'
If you work with userdata you probably want to do the above using the C API. However the Lua code should make it clear extactly which steps are necessary. (The newproxy(..) function simply creates a dummy userdata from Lua.)
I gave up trying to do this in C++ so I did it in lua. I loop through all the metatables (_R) and assign the meta methods.
_R.METAVALUES = {}
for key, meta in pairs(_R) do
meta.__oldindex = meta.__oldindex or meta.__index
function meta.__index(self, key)
_R.METAVALUES[tostring(self)] = _R.METAVALUES[tostring(self)] or {}
if _R.METAVALUES[tostring(self)][key] then
return _R.METAVALUES[tostring(self)][key]
end
return meta.__oldindex(self, key)
end
function meta.__newindex(self, key, value)
_R.METAVALUES[tostring(self)] = _R.METAVALUES[tostring(self)] or {}
_R.METAVALUES[tostring(self)][key] = value
end
function meta:__gc()
_R.METAVALUES[tostring(self)] = nil
end
end
The problem with this is what I'm supposed to use for index. tostring(self) only works for those objects with an ID returned to tostring. Not all objects have an ID such as Vec3 and Ang3 and all that.
You could also use a simple table...
config = { tooltype1 = "Tool",
tooltype2 = "HopperBin",
number = 5,
}
print(config.tooltype1) --"Tool"
print(config.tooltype2) --"HopperBin"
print(config.number) --5

Resources