64 posts
Posted 14 March 2014 - 04:24 PM
how do I write a metatable to detect changes in its values? the end product I'm looking for is a way to act upon changes made based on the change done.
say if I'm storing the scale of a monitor in a.scale, how do I detect the change, and change the scale of the monitor? (following code is current iteration of a button API as I learn about metatables)
local button = {
display = function (self) -- Draw the buttons on screen
self.mon.clear()
self.mon.setCursorPos(2,2)
self.mon.write("X")
end,
new = function (self) -- Add button to system
end,
delete = function (self) -- removes button from system
end,
handleEvents = function (self) -- event handler for the API
print("test")
end,
toggleStatus = function (self) -- toogles the status of the button
end,
}
local scale = {
test = function ()
print("test")
end
}
function new(side)
local newInstance = {
side = side,
mon = peripheral.wrap(side),
Data = {},
size = {},
scale = 1
}
print(newInstance.mon.getSize())
newInstance.size.x, newInstance.size.y = newInstance.mon.getSize()
setmetatable(newInstance, {__index = button})
return newInstance
end
also is it possible to reference a table a metatable is stored in? (required for future Ideas for the code above)
Edited on 14 March 2014 - 03:29 PM
8543 posts
Posted 14 March 2014 - 04:37 PM
You'd use the __newindex metamethod, iirc. You should be able to reference the table as an upvalue if you declare the function after you've declared the table, within the same scope.
Edit: also, I believe the newindex metamethod is passed table, key, newValue, so you can simply use than in your function.
64 posts
Posted 14 March 2014 - 05:14 PM
so the following should work:
if key == "scale" then
self.mon.setTextScale(newValue)
self.scale = newValue
else
self[key] = newValue
end
but could it cause a infinite loop?
1281 posts
Posted 14 March 2014 - 06:23 PM
I've never tried, but i suspect it might. You have to use rawset(table,index,value) to bypass newindex. However, the following function approach is probably more suited, since newindex is only triggered if the index dosen't already exist.
scale = function(self, scale)
self.mon.setTextScale(scale)
self.scale = scale
end
Alternatively you would have to use two tables, one to assign the value to, which then passes it on to a second one via newindex. Then uses index to get the value from the second table whenever it's requested.
Edited on 14 March 2014 - 06:56 PM
64 posts
Posted 15 March 2014 - 05:31 AM
I've never tried, but i suspect it might. You have to use rawset(table,index,value) to bypass newindex. However, the following function approach is probably more suited, since newindex is only triggered if the index dosen't already exist.
scale = function(self, scale) self.mon.setTextScale(scale) self.scale = scale end
Alternatively you would have to use two tables, one to assign the value to, which then passes it on to a second one via newindex. Then uses index to get the value from the second table whenever it's requested.
I have already started to implement the function, but I like the second table Idea. my only question is how can I keep some kind of flexibility, like being able to have multiple instances(one for each side for example)
7508 posts
Location
Australia
Posted 15 March 2014 - 06:11 AM
so the following should work:
if key == "scale" then
self.mon.setTextScale(newValue)
self.scale = newValue
else
self[key] = newValue
end
but could it cause a infinite loop?
assuming the code is in the
__newindex metamethod then yes, it will cause a recursive loop. to circumvent this you make use of
rawset; when attempting to get variables you should use
rawget.
I have already started to implement the function, but I like the second table Idea. my only question is how can I keep some kind of flexibility, like being able to have multiple instances(one for each side for example)
Assuming I understand what you're asking here the best way is after wrapping your peripherals looping through them and then replacing the appropriate functions, making sure to reference back to the original monitor object.
Edited on 15 March 2014 - 05:15 AM
64 posts
Posted 15 March 2014 - 07:12 AM
I have already started to implement the function, but I like the second table Idea. my only question is how can I keep some kind of flexibility, like being able to have multiple instances(one for each side for example)
Assuming I understand what you're asking here the best way is after wrapping your peripherals looping through them and then replacing the appropriate functions, making sure to reference back to the original monitor object.
He talked about referencing a table to store and call the data, and my code uses one variable per side set by the user. I was looking for something like what he was talking about because it will solve the original question.
I know I will need some kind of cross talk ability, but I know that would need to store a reference to a table and not the table as a value, or something like that.
1281 posts
Posted 15 March 2014 - 09:48 AM
I was thinking something along these lines. Idk how well it would work, as i've never done it, but it's theoretically sound as far as i can tell.
function new()
local obj
obj = setmetatable(
{
values = {
--default values go here
}
},
{
__index = obj.values,
__newindex = function(t,k,v)
--newindex functionality goes here
obj.values[k] = v
end
}
}
return obj
end