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

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()

Related

OOP Help - How do I get this code block to recognize one of its arguments?

I'm learning Lua and how to implement OOP. Trying out a test example of an object seems to return one of the argument of the object as 'null' despite being assigned one.
function Character(Name, Level, Class) --Constructor
return {GetName = T.GetName, GetLevel = T.GetLevel, GetClass = T.GetClass}
end
end
-- Snippets
Player = Character("Bob", 1, "Novice")
When I try printing Player.GetName() it returns null instead of Bob. Where have I gone wrong?
Here is the full code.
OOP in Lua takes a bit more than what you have done there, you will want to make use of metatables and upvalues.
-- How you could define your character structure.
local Character = {}
function Character.GetName(self)
return self.name
end
function Character.new(Name, Level, Class)
local _meta = {}
local _private = {}
_private.name = Name
_private.level = Level
_private.class = Class
_meta.__index = function(t, k) -- This allows access to _private
return rawget(_private, k) or rawget(Character, k)
end
_meta.__newindex = function(t, k, v) -- This prevents the value from being shaded
if rawget(_private, k) or rawget(Character, k) then
error("this field is protected")
else
rawset(t, k, v)
end
end
return setmetatable({}, _meta) --return an empty table with our meta methods implemented
end
This creates a local table _private when you create a new instance of a Character. That local table is an upvalue to the _meta.__index and it cannot be accessed outside the scope of the Character.new function. _private can be accessed when __index is called because it is an upvalue.
-- How to use the character structure
player = Character.new("Bob", 10, "Novice")
npc = Character.new("Alice", 11, "Novice")
print(player:GetName())
I use player:GetName(), but in all honesty you can just do player.name as well.
Resources for more on this topic:
http://tutorialspoint.com/lua/lua_metatables.htm
http://lua-users.org/wiki/ObjectOrientationTutorial

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.

How does `table.insert` work with custom tables in Lua

I wonder how does table.insert work in lua?!
I am asking this because I have tried to use it on a custom table with __newindex metamethod
but it seems not to call it. Is there a way to make my custom table functionality to work with table.insert?!
From my humble knowledge about the language I would say it uses something like rawset or something maybe I donno.
Sample I worked on:
do
tabl = {1,2,3}
local _tabl = tabl
tabl = {}
local mt = { __newindex = function(t,k,v) print"changing" ;_tabl[k] = v end, __index = _tabl}
setmetatable(tabl,mt)
end
tabl[4] = 4; --prints "changing"
table.insert(tabl,5) -- prints nothing!!
There's no such metamethod, table.insert just inserts a new value to a specified table.
local myTable = {}
table.insert(myTable, "somestring")
-- so now myTable has one value, myTable = { "somestring" }
It works like:
local myTable = {}
myTable[#myTable + 1] = "somestring"
__newindex metamethod affects only assignment operator "=", table.insert is just a separate function not related with metatables, you can modify the behaviour of this function if you want:
_tableinsert = table.insert
function table.insert(t, v)
-- here your actions, before real function will be used
_tableinsert(t, v)
end
I think that would be possible to make your own metamethod __tableinsert this way.
table.insert does, in fact, use rawset. See the lua 5.1 source here.
As indicated if you do the assignment yourself you should be able to get the behavior you want.

Lua Metatables - calling functions with colon syntax

I have the following problem, somebody can help me?
comp = {}
comp.__index = function(obj,val)
if val == "insert" then
return rawget(obj,"gr")["insert"]
end
return rawget(obj, val)
end
comp.new = function()
local ret = {}
setmetatable(ret, comp)
ret.gr = display.newGroup()
return ret
end
local pru = comp.new()
pru.gr:insert(display.newImage("wakatuBlue.png"))
This line works, but I don't want to access the insert method using the gr property, I want to call the insert method directly and the metatable __index function does the work
pru:insert(display.newImage("wakatuBlue.png"))
This line doesn't work and I get this error: "bad argument #-2 to 'insert' (Proxy expected, got nil)", but this is the way that I'm looking to use
Do you want something like this?
comp = {}
comp.__index = function(obj,val)
if val == "insert" then
return rawget(obj,"gr"):insert(val)
end
return rawget(obj, val)
end
__index works just fine; it's because your last call is interpreted as:
pru.insert(pru, display.newImage("wakatuBlue.png"))
whereas you want/need it to be:
pru.insert(pru.gr, display.newImage("wakatuBlue.png"))
You either need to call it like this or explain what you are trying to do.

How can I change every index into a table using a metatable?

I'm trying to write a metatable so that all indexes into the table are shifted up one position (i.e. t[i] should return t[i+1]). I need to do this because the table is defined using index 1 as the first element, but I have to interface with a program that uses index 0 as the first element. Since reading Programming in Lua, I think that I can accomplish what I want with a proxy table, but I can't seem to get it working. So far, I have this:
t = {"foo", "bar"}
local _t = t
t = {}
local mt = {
__index = function(t, i)
return _t[i+1]
end
}
setmetatable(t, mt)
However, this does not create the expected result. In fact, it doesn't return any values at all (every lookup is nil). Is there a better way to do this, or am I just missing something?
t = {"foo", "bar"}
local _t = t
t = {}
local mt = {
__index = function(t, i)
return _t[i+1]
end
}
setmetatable(t, mt)
print(t[0])
outputs "foo" for me when run here: http://www.lua.org/cgi-bin/demo

Resources