Jump to content




Lua tables: bad code or Lua/LuaJ bug?

lua

  • You cannot reply to this topic
5 replies to this topic

#1 MKlegoman357

  • Members
  • 1,170 posts
  • LocationKaunas, Lithuania

Posted 13 July 2013 - 05:58 PM

Hello pros,

I was creating my program, making clickable buttons. They worked perfectly as expected. It was done by creating a table called "button" and implementing in it some functions to handle buttons. Buttons are created and saved in the same table ("button") called "buttons":
local button = {
buttons = {},

add = function (self, and other variables)
  --blah, blah
end,

remove = function (same stuff)
  --another function
end,

--More functions...
}
Now, I didn't want all of my buttons to be in button.buttons table, so I wrote this:
local butt1 = setmetatable({}, {__index = button})
local butt2 = setmetatable({}, {__index = button})

butt1:add("blah, blah", arguments...)
butt1:draw()

This worked as expected, so I wanted to check what will the code do if there is no buttons in the "buttons" table, so I tried to draw buttons from the "butt2" table:
butt2:draw()
And it did draw a button, the one that I created in the "butt1" table. So I was searching how to fix it and I found it. I deleted the "buttons" table from "button" table:
local button = {
--removed the "buttons = {}," line

add = function (self, and other variables)
  --blah, blah
end,

remove = function (same stuff)
  --another function
end,

--More functions...
}
and defined that table in the setmetatable method:
local butt1 = setmetatable({buttons = {}}, {__index = button})
local butt2 = setmetatable({buttons = {}}, {__index = button})
and then "butt2:draw()" didn't draw any buttons (as it should be).

So, my question is that:
Why is it behaving like that? Maybe "setmetatable()" method is making table "buttons" public to every other instance (wrong word, don't remember other words) of "button" table?

Here are the codes (just run it in CC, they don't error):
Working:
Spoiler

Not Working:
Spoiler


#2 MysticT

    Lua Wizard

  • Members
  • 1,597 posts

Posted 13 July 2013 - 06:31 PM

That's how metatables work. The __index metamethod will search the referenced table for the given key if it doesn't exist in the table.
Example:
local someTable = {
key1 = "Hello World!",
key2 = 2
}

local tbl = {
key2 = 10,
key3 = "Some Random String"
}
setmetatable(tbl, { __index = someTable })

print(tbl.key1) -- this will print "Hello World!", from someTable, because the key is not in tbl
print(tbl.key2) -- this will print 10, as the key is present in tbl
print(tbl.key3) -- this will print "Some Random String"

So, when doing oop in lua, you need to define the functions and common variables in the metatable, and "instance" variables in the instance table. Something like this:
local Class = {}

function Class:doSomething()
  print("Test")
end

function Class:test()
  print(self.value)
end

local obj = setmetatable({}, { __index = Class })
obj.value = 10 -- set value in the instance object
obj:doSomething()
obj:test() -- this should print 10, the value we just assigned to obj.value

Hope you understand all that. If you don't, or want to know something else, just ask :)

#3 MKlegoman357

  • Members
  • 1,170 posts
  • LocationKaunas, Lithuania

Posted 13 July 2013 - 06:42 PM

View PostMysticT, on 13 July 2013 - 06:31 PM, said:

Spoiler

Thanks for the help! This really helped me.

#4 MKlegoman357

  • Members
  • 1,170 posts
  • LocationKaunas, Lithuania

Posted 13 July 2013 - 06:53 PM

Well, this code is working properly (note: it is working the same way that my Non-Working code works):
local but = {
n = 1,

a = function (self)
  self.n = 2
end,

b = function (self)
  self.n = 1
end
}

local but1 = setmetatable({}, {__index = but})
local but2 = setmetatable({}, {__index = but})

print(but1.n)
print(but2.n)

but1:a()

print(but1.n)
print(but2.n)

Maybe you can explain why is it not happening the same as it was with the buttons?

EDIT: This code is working fine, that's why I though it could be Lua/LuaJ bug.

#5 MysticT

    Lua Wizard

  • Members
  • 1,597 posts

Posted 13 July 2013 - 09:27 PM

Well, it works because the first "n" value referenced is the one on the shared table. But, when you assign a value to self.n, self is referencing the "btn1" table, so it sets "n" to 2 in that one, not the shared one. See the comments:
local but = {
n = 1, -- shared n, initialized to 1

a = function (self)
  self.n = 2 -- self is the passed argument, not the "but" table
end,

b = function (self)
  self.n = 1
end
}

local but1 = setmetatable({}, {__index = but})
local but2 = setmetatable({}, {__index = but})

print(but1.n) -- both this "n" references are to the shared value
print(but2.n)

but1:a() -- this would call but.a(but1)

print(but1.n) -- but1.n was set before, so it takes that value
print(but2.n) -- but2.n is not defined, so it uses but.n (the shared value)


#6 MKlegoman357

  • Members
  • 1,170 posts
  • LocationKaunas, Lithuania

Posted 14 July 2013 - 01:27 AM

View PostMysticT, on 13 July 2013 - 09:27 PM, said:

Well, it works because the first "n" value referenced is the one on the shared table. But, when you assign a value to self.n, self is referencing the "btn1" table, so it sets "n" to 2 in that one, not the shared one. See the comments:
local but = {
n = 1, -- shared n, initialized to 1

a = function (self)
  self.n = 2 -- self is the passed argument, not the "but" table
end,

b = function (self)
  self.n = 1
end
}

local but1 = setmetatable({}, {__index = but})
local but2 = setmetatable({}, {__index = but})

print(but1.n) -- both this "n" references are to the shared value
print(but2.n)

but1:a() -- this would call but.a(but1)

print(but1.n) -- but1.n was set before, so it takes that value
print(but2.n) -- but2.n is not defined, so it uses but.n (the shared value)

With few more tests and your good explanation I found what was wrong. My problem was that I tried to put buttons into a not existing table, so lua was just using the "shared" table of buttons. Same thing when getting values. Thank you very much MysticT!





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users