This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Engineer's profile picture

[Advanced] OOP, method is nil ~!SOLVED!

Started by Engineer, 02 June 2013 - 10:59 AM
Engineer #1
Posted 02 June 2013 - 12:59 PM
Hello all,

I am going to build a GUIBuilder, I have some pretty awesome ideas for it. But I'm stuck and that has to due with Object Oriented Programming. Here is the code:

–[[ Link removed, I want to make the progress secret, now it has been fixed! :P/> ]]

I created this specific function:

function scrollBox:drawBox()

		paintutils.drawLine( self.xMin, self.yMin, self.xMax, self.yMin, self.colour_out )
		paintutils.drawLine( self.xMin, self.yMin, self.xMax, self.yMax, self.colour_out )
		paintutils.drawLine( self.xMin, self.yMin, self.xMin, self.yMax, self.colour_out )
		paintutils.drawLine( self.xMax, self.yMin, self.xMax, self.yMax, self.colour_out )

		-- stub
end

But when I try to call that method on line 152, it attempts to call nil. But the thing is, it is almost the same as the frame function, but the difference is the table. It is a very odd error to happen there, maybe it is some sort of bug ( I suppose not, but it might be.. )

I have no idea what's causing it, and thats why I came here for help.

Thank you for reading, and/or helping me!
Edited on 02 June 2013 - 12:34 PM
Symmetryc #2
Posted 02 June 2013 - 01:09 PM
Hey Engineer :P/>. I don't think that you defined the new:drawBox().
H4X0RZ #3
Posted 02 June 2013 - 01:10 PM
Try

function scrollBox.drawBox(self)
--some stuf
end


never mind
Engineer #4
Posted 02 June 2013 - 01:17 PM
Hey Engineer :P/>. I don't think that you defined the new:drawBox().

But then, why does the commented out frame part, work? I tested it, and that does work.. :huh:/>
Symmetryc #5
Posted 02 June 2013 - 01:20 PM
Because your returning "self" which is the table of frame, which contains the function draw(), but when you just return an empty table, it contains no functions :P/>.
Engineer #6
Posted 02 June 2013 - 01:22 PM
Because your returning "self" which is the table of frame, which contains the function draw(), but when you just return an empty table, it contains no functions :P/>.
Wow, this is embarrassing.. Thanks :D/>
Symmetryc #7
Posted 02 June 2013 - 01:25 PM
No problem XD.
Yevano #8
Posted 02 June 2013 - 01:40 PM
Edit: Ninja'd :P/> I'll keep this here, though.

I think it's happening because the __index of the metatable doesn't reference to the scrollBox table. To fix this, you would have to add scrollBox to your _mt._scrollBox table. Also, I should warn you that your way of doing OOP is probably going to cause you to break your own code pretty often having to keep up with all those metatables. You're also doing this: someClass:new() blah end. Just use "." instead of ":" since you don't need to pass an instance variable for constructor functions. This is the way I typically do OOP:


local SomeClass = { }
SomeClass.__index =  SomeClass

function SomeClass.new(a, b, c)
	self = { }
	self.a = a
	self.b = b
	self.c = c
	return setmetatable(self, SomeClass)
end

function SomeClass:doSomething()
	return self.a + self.b * self.c
end
Engineer #9
Posted 02 June 2013 - 02:25 PM
Edit: Ninja'd :P/> I'll keep this here, though.

I think it's happening because the __index of the metatable doesn't reference to the scrollBox table. To fix this, you would have to add scrollBox to your _mt._scrollBox table. Also, I should warn you that your way of doing OOP is probably going to cause you to break your own code pretty often having to keep up with all those metatables. You're also doing this: someClass:new() blah end. Just use "." instead of ":" since you don't need to pass an instance variable for constructor functions. This is the way I typically do OOP:


local SomeClass = { }
SomeClass.__index =  SomeClass

function SomeClass.new(a, b, c)
	self = { }
	self.a = a
	self.b = b
	self.c = c
	return setmetatable(self, SomeClass)
end

function SomeClass:doSomething()
	return self.a + self.b * self.c
end
I dont get how I can break my own code with this style of OOP. Can you please explain that?

And of courseI have to use the colon in someClass:new(), because I am return a self argument. This would be the table, if I would use a dot, I have to pass the self argument to the arguments. So I get function someClass.new( self ). You can escape the self using the colon.. :P/>
Yevano #10
Posted 02 June 2013 - 02:45 PM
If I understand correctly from looking at your code, the instances you are returning from your create functions are just the class table. If you try to create more than one of any of those components, they will overwrite each other.
Symmetryc #11
Posted 02 June 2013 - 02:48 PM
Well, you're returning the table of functions that make objects to the objects, new() function and all :P/> . It it would be be better practice to create a "model" object that is modified by the arguments of the object creating function and returned by it. This way, you only have to change the "model" object.
Engineer #12
Posted 02 June 2013 - 03:15 PM
If I understand correctly from looking at your code, the instances you are returning from your create functions are just the class table. If you try to create more than one of any of those components, they will overwrite each other.

Can you give me an example where objects dont override each other?
Yevano #13
Posted 02 June 2013 - 03:29 PM
The example I already gave you is one :P/>. Note that in the constructor I create a new self variable instead of using the self parameter given by the function caller. This way, you are creating a new object and setting its metatable to the class table. The class table sets its __index metamethod so that all objects of the class have access to the instance methods.
Engineer #14
Posted 02 June 2013 - 03:35 PM
A constructor like this would be alright?:

local x = {}
--local x.__index = x --# can you explain this, I dont quite get the purpose of this

function x.create()
   local self = {}
   return setmetatable( x, {__index = x })
end
Is this about right, note that I have commented out the x.__index = x
Yevano #15
Posted 02 June 2013 - 03:45 PM
I personally use the class as the metatable so that you can override metamethods on the objects. This way you can do things like this:


function SomeClass:__add(other)
    return SomeClass.new(self.a + other.a, self.b + other.b, self.c + other.c)
end

-- Now you can do this
local bar = SomeClass.new(1, 2, 3)
local foo = SomeClass.new(3, 2, 1)
local baz = foo + bar