Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Metatable/Object Oriented Programming help?

Im trying to understand how metatables work and what object oriented programming actually is. I've encountered something i can't figure out.

Account = {}

function Account.new(value)
    return setmetatable({balance = value}, Account)
end
Account.__index = Account --THIS LINE

function Account:withdraw(v)
    self.balance = self.balance - v
end
function Account:deposit(v)
    self.balance = self.balance + v
end
function Account:__tostring()
   return "Account(" .. self.balance .. ")"
end

b = Account.new(100)
b:deposit(10)
print(b.balance)

This is copy pasted from the Roblox Wiki. I can't figure out what the 6th line is for, the script doesn't work without it and the error code says "Workspace.Script:21: attempt to call method 'deposit' (a nil value)" so im completely lost. If anyone could explain to me how this script exactly works i'd be grateful.

1 comment

1 answer

✓ Accepted answer

A quick glance can mislead you into thinking that Account is the object when it is not. Line 4 creates a new object, because setmetatable returns its first argument. The only defined key in this object is "balance" as you can see here {balance = value}.

This makes for a very boring table. Thankfully, this table has a metatable. The details of this metatable have been outlined in the surrounding lines. The variable Account points to this metatable.

Now, our table that we created before can access deposit and withdraw only because of line 6. The __index metamethod by default will make the table search for contents in the metatable itself if a key cannot be found within the table.

Really sorry that you were confused by this. This was a horrible example ripped right out of a page from the Lua website. In reality, your code should separate your constructor, object table, and metatable. This example fails to do that by combining constructor and metatable, as well as throwing some methods that could have just been defined in the object table right in the metatable. People often do this because it is more memory efficient, and to that I laugh because working solely in a scripting language means you have nearly no right or need to fuss over such petty optimization details.

Here's is a cleaned up, and arguably easier to understand, implementation of the sample you shared. I made sure to clearly separate constructor, object table, and metatable so it should be much easier to learn from it.

local Account = { }
local Account_Metatable = {
  __tostring = function(self)
    return "Account(" .. self.balance .. ")"
  end
}

function Account.new(value)
  local Object = {balance = value}
  function Object:withdraw(v)
    self.balance = self.balance - v
  end
  function Object:deposit(v)
      self.balance = self.balance + v
  end
  return setmetatable(Object, Account_Metatable)
end

b = Account.new(100)
b:deposit(10)
print(b.balance)

7 comments

0

Looking at this, other scripts and youtube tutorials at the same time to understand how they really connect together. Only getting more confused :s Thanks for the well-written reply. I noticed the _tostring has no effect on the script, it works without it aswell. Im really failing at understanding this, the only place Account is used is Account.new, i'm not even sure if they're related in anyway.

0

Account exists as a table to hold a constructor. The general idea is sometimes there may be functions independent of individual objects (like creating objects, for example with "new").

0

As for your __tostring comment, that's more of a metamethod thing. It appears you don't quite understand those. __tostring exists here so you can do print(b) and get a formatted output, or concatenate it.

0

I can just replace the setmetatable part with "return Object", and it pretty much does the same thing. What's the point of the metatable in the first place?

0

YonaJune's code creates a new method for each and every object that you create. Your original code does not -- which is what the metatable is for. The metatable approach is a little "safer" -- you can add checks that will error if you try to grab something that doesn't exist, and you can prevent the methods from being redefined.

0

BlueTaslem is right. I am a strong believer that you shouldn't start using that approach until you've really grasped metatables, though. You should read up on those first before tackling OOP. You will understand both sides rather well if you do that rather than being clueless.

0

Thanks a lot guys

This discussion is preserved as it was. New answers, comments, and votes are closed.