2

I'm fairly new to Lua and I am trying to get a class system to work. What I would like to do it to have a base class which has a bunch of properties and then extend this class for objects such as buttons, textboxes, etc.

The base class will have properties such as x, y, width, height etc and then the other classes will have, say, label or colour or similar.

If I create a function such as render() on the base class, and try to override this function later on, it doesn't seem to work. (Presumably I'm using classes completely wrong!)

Here is a reproduction down example of what I am using:

Base = {}
Base.__index = Base
function Base.create(value)
    local b = {}
    setmetatable(b, Base)
    b.value = value
    return b
end

function Base:render()
    print("I'm the base! : "..self.value)
end

Button = {}
Button.__index = Base

function Button.create(value)
    local b = Base.create(value)
    setmetatable(b, Button)
    return b
end

function Button:render()
    print("I'm a button! : "..self.value)
end

Button.create("TestBtn"):render()

What I would like the Button.create("TestBtn"):render() do is to print I'm a button! : TestBtn however it prints I'm the base! : TestBtn.

Could someone help me to override the original render function with this new one?

Thanks, Will.

5
  • Button.__index = Base is incorrect. Notice how that's the same as Base.__index = Base Commented Oct 21, 2014 at 12:47
  • @Etan Okay then. I thought that was how the inheritance did its magic. So, what am I missing or doing wrong? Commented Oct 21, 2014 at 12:53
  • 2
    Well, so I think I was a bit abrupt there. That is correct for chaining Button to Base. The issue is that you aren't using Button itself as __index on anything. You need to setmetatable(b, {__index = Button}) in Button.create I believe. Sorry about that. Commented Oct 21, 2014 at 12:58
  • Ah, that works now. Wonderful. Thank you very much :) I think I am misunderstanding the use of __index and metatable a bit. I better look that up. If you wanna add your comment as an answer I'll mark it as correct for you. Commented Oct 21, 2014 at 13:06
  • 1
    No, Button.__index = Button actually was correct. This makes the methods defined in the Button class available to the objects created in Button.create (Button is used both as the metatable for button objects and as the table holding the button methods). What was missing is the inheritance link between base class and derived class: setmetatable(Button, Base)! Commented Oct 21, 2014 at 14:03

2 Answers 2

1

The missing detail, as @siffiejoe mentioned and I hinted at, is that as written your Button objects don't know to look in the Button table for methods.

My solution created garbage tables to create that association and so isn't really the best solution but illustrated the point.

@siffiejoe's answer is better in that it more accurately codifies the desired functionality and relationship. It also then requires the extra step of chaining the "class" tables (i.e. setmetatable(Button, Base)).

The key here is the operation of the index metamethod. This is described with code in the lua Reference Manual:

"index": The indexing access table[key].

function gettable_event (table, key)
   local h
   if type(table) == "table" then
     local v = rawget(table, key)
     if v ~= nil then return v end
     h = metatable(table).__index
     if h == nil then return nil end
   else
     h = metatable(table).__index
     if h == nil then
       error(···)
     end
   end
   if type(h) == "function" then
     return (h(table, key))     -- call the handler
   else return h[key]           -- or repeat operation on it
   end
end
Sign up to request clarification or add additional context in comments.

Comments

0

Define Button:render instead of Button:test.

1 Comment

Thanks for your reply. That was rather stupid of me! However it still seems to run the Base:render() instead: codepad.org/AfODqE9J

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.