Thank you. Of course I saw this article as it’s the first in googling this subject. But it doesn’t work for me either. I get nil error or stack overflow error (when using “self.class.__classDict” instead of “Test.__classDict”).
And my point is to write a simple getter (and setter) for a property - nothing more. If you’ll run my code you’ll see the problem. And I got really stuck with it.
Does anybody use getters in Codea? Could you share some example code please?
@Iavmax I haven’t the slightest idea of what your trying to do, but I took your code and was playing with it. If I take the () off the line print( obj.greeting,obj.name) I don’t get an error, but I’m not sure what result I’m supposed to get. Maybe this will help some.
Foo = class()
function Foo:greeting()
return "My name is"
end
function setup()
local obj = Foo()
print(obj.greeting, obj.name)
end
function Foo:__index(key)
if key == "name" then
return "foo"
else
return rawget(self, key)
end
end
@Iavmax Like I said above, I don’t know what you’re trying to do but here’s what I found out playing with the code. Apparently by using __index, you’re reading a table. That table is the self values that get created in Foo: init(). It doesn’t look like anything other than __index gets called using obj. If I run this code, I think it prints what you’re after. Also, when you hit the return rawget code in the function Foo:__index(key), it calls Foo__index again and goes into an infinite loop and causes an error.
function setup()
local obj = Foo()
print(obj.greeting, obj.name)
end
Foo = class()
function Foo:init()
self.greeting="My name is"
end
function Foo:__index(key)
if key == "name" then
return "foo"
else
return rawget(self.key)
end
end
@Iavmax I also found this. Again, not sure if this is what you’re after but it seems to allow you to set values and read them back.
function setup()
foo = MyClass()
foo.testMember = 5
foo.testMember = 2
print( foo.testMember )
end
MyClass = class()
function MyClass:init()
self.members = {}
end
function MyClass:__newindex( index, value )
if index == "testMember" then
self.members[index] = value
print( "Set member " .. index .. " to " .. value )
else
rawset( self, index, value )
end
end
function MyClass:__index( index )
if index == "testMember" then
print( "Getting " .. index )
return self.members[index]
else
return rawget( self, index )
end
end
@Iavmax I just realized the code I have above is the same code in your link from your first post. The code I show above seems to work if I understand getters and setters correctly. So I’m not sure why you say in your first post that it doesn’t work.
@lavmax Why do you even want to make getters and setters? They’re usually only used in OOP, when you have a private variable that other classes can’t reach without a getter/setter. In Lua, there are no private variables, and you could access any variable from any class. The only place I could see you needing this is if you have a variable that is local to a tab, but then, couldn’t you just simply have 2 functions, one setting the variable, and the other returning it?
@dave1707 The problem is that your code (and mine) is not working. Just add any function to your class and you’ll get an error. Like this
function setup()
foo = MyClass()
foo.testMember = 5
foo.testMember = 2
print( foo.testMember )
foo:foo()
end
MyClass = class()
function MyClass:init()
self.members = {}
end
function MyClass:foo()
print("functions work too")
end
function MyClass:__newindex( index, value )
if index == "testMember" then
self.members[index] = value
print( "Set member " .. index .. " to " .. value )
else
rawset( self, index, value )
end
end
function MyClass:__index( index )
if index == "testMember" then
print( "Getting " .. index )
return self.members[index]
else
return rawget( self, index )
end
end
And who needs a class without functions. Theoretically there should be a property __classDict that holds class functions, but in Codea it is nil. So may be @Simeon could bring some light into the subject.
@SkyTheCoder I need it for dynamic properties, that are calculated, not stored. Of course I can use c++ style with getter/setter functions, but it’s very ugly and uncommon in languages like lua.
@Iavmax When you create a class, you create the metatable of the following instances. In your example, the method foo is linked to the metatable of the instance foo (foo = MyClass). In the __index getter, self refer to the instance, not it’s metatable. A silly fix to illustrate:
function MyClass:__index( index )
if index == "testMember" then
print( "Getting " .. index )
return self.members[index]
else
if index == "foo" then
return rawget(getmetatable(self), index)
end
return rawget( self, index )
end
--[[ or handle all case with
else
return rawget(getmetatable(self), index) or rawget( self, index )
end]]
end
@Iavmax Here’s a way that I came up with. It does the __index and __newindex methods and also any class function. I added some examples of using the index and newindex methods. Not sure if this is what you’re after, but I’m learning about metatables.
function setup()
z=xx() -- create instance of xx
z:update(10,12345) -- update key 10 with value 12345
z:read(10) -- read key 10
z:read(2) -- read key 2, error, key doesnt exist
z:update(24,10) -- update key 24 with value 10, value out of range for key
z:test() -- call function test
end
xx=class()
function xx:init()
self.tab1={} -- table for values
self.tab2={} -- table for meta methods
setmetatable(self.tab1,self.tab2)
-- create meta function for table read
self.tab2.__index=
function(tab,key)
local r=rawget(tab,key) -- read table
if r==nil then -- entry not found
return "key not found"
else
return r
end
end
-- create meta function for table update
self.tab2.__newindex=
function(tab,key,val)
if key==24 and (val<20 or val>30) then -- set limit for key
print("key "..key,"value "..val.." out of range, not updated")
else
rawset(tab,key,val) -- update table
end
end
end
function xx:update(k,v)
print("update key "..k.." with value "..v)
self.tab1[k]=v
end
function xx:read(k)
print("read key "..k.." ",self.tab1[k])
end
function xx:test()
print("the test function was called")
end
@lavmax you’re right, I’ve blended the way I usualy implement getters with your example (a single case property lookup). So to respect the property lookup chain, something like this should be better
function MyClass:__index( index )
return self.members[index] or getmetatable(self)[index]
end