I’m pretty new with metatables and metamethods… but I’ve seen their power through Lua OOP.
Right now I’m trying to return a string everytime I reference a table. For example:
-- OBJECTIVE: I want to print "lol" when I do print(myTable)
local MyTable = {"lol", true, 6}
print(myTable) -- Output: scrambled characters and numbers
I’ve been searching around the internet for a metamethod which returns a string when its table is called, but I can’t find it.
Is there an easier way to write this? I appreciate the response, it’s just that I don’t like tables taking up too much of my monitor space. This is the most compact I can make mine:
I’d just like to take the time to point out that the “scrambled” text returned by printing the table without a __tostring metamethod is the address of the table. It’s not exactly scrambled or random.
There isn’t. That’s as simple as it gets. The way you’ve written it is the exact same as how HaxHelper wrote it except with less line breaks and an ambiguously checked index (which is bad practice - tostring will return whatever is at index 1, which may give you an unexpected result).
Yes you do. Metamethods only accept table or function values (context-based - some accept both types, some accept only one type or the other). There are exceptions for a few though, such as setting __metatable to a string.
print calls tostring on its arguments, so if you overwrite tostring then you don’t need to use metamethods. __tostring isn’t technically a metamethod anyway, it’s just something tostring respects.
I guess I didn’t know I had to assign functions to almost every metamethod before because I only used the __index metamethod which didn’t require a function attached. The wiki helped me a bit with that, too.
Here’s the corrected code that I use which works now:
-- MODULE SCRIPT
local PlayerData = {}
local MetaMethods = {
__index = PlayerData,
__tostring = function(self)
return self.Name
end
}
setmetatable(PlayerData, MetaMethods)
function PlayerData.new(Player)
local self = {}
setmetatable(self, MetaMethods)
self.UserId = Player.UserId
self.Name = Player.Name
self.Points = 0
return self
end
return PlayerData
I corrected my response a bit here. Correction is italicised in the below quote.
It typically varies from method to method. Conveniently, __index can accept a table value that you can attach as meta, but it can also accept a function. Just thought you’d like to know in case you ever find yourself needing (or wanting) to use that in the future. Also helps for knowledge’s sake.
__index = function(self, index)
print("Wow!", index)
end
}
The only two methods that I know of that aren’t restricted to function and/or table values are __metatable and __mode. __metatable returns whatever you set to it when getmetatable is called on an object. Roblox’s instances incorporate this as well.
__metatable = "The metatable is locked"
I have no clue what __mode does, but I do know that you can set it to either “v” or “k”. There’s most likely a tutorial from a Lua site that explains what it’s used for.
__mode describes how the table is weak, for more info see here. __mode allows you to create weak keys, weak values, or both. Using weak references is sometimes important as you don’t have to manually remove the reference.
So essentially the v is for value and the k is for key, while using the __mode metamethod allows you to create weak tables via metamethods? I see. This was the only real thing I was confused about. I’m not too sure if I’ll see myself having any use for it, but maybe I will. Cheers.
Thanks for the convenient __index trick, bro. I appreciate it.
I’ve got one more question:
I have a table called Players. Players contains other tables inside it, too - which are automatically generated when a player joins the server. Each table inside Players contains information about each player, like their UserId, how many points they have, etc.
I want the table structure to look like this (visual reference not actual code):
I wouldn’t recommend it and I’d just go with a key-value pair in any case simply because it voids any weird issues or cases that you need to cover for. I always am sure to set a key unless having a key is unnecessary for my use case.
Which in a metamethod format wrapped around the player’s table (and NOT Players) would look something like this:
__index = function(self, index)
if index == "Points" then
return self[3]
end
end
As I said before, I don’t recommend doing this kind of ambiguous searching though unless it’s not important to know what a key is. Plus, you need to ensure that you need to strictly follow conventions to avoid any real issues. I wouldn’t bother trying to complicate code while sacrificing readability or efficiency.
That being said, there is no workaround other than what I’ve listed above to do Table.Points on your copy. Points is the index which will be looked up on the table. If there’s no index metamethod to catch that nil index, you’ll be returned with nil.
They don’t necessarily have to be “k” or “v”. From testing if you set __mode to anything other than a string, then it will act like a normal table. If __mode is a string and it finds the letter v (specifically lowercase) then its values will be weak. This works the same way for weak keys so if __mode is a string and it find the letter k (specifically lowercase) then its keys will be weak.
For example,
Setting __mode to “Uv” would make the table have weak values, just like setting __mode to “v” would, but setting __mode to “UV” wouldn’t make the table have weak values.
You can also use both weak keys and weak values like this
local t = setmetatable({},{__mode = "kv"})
-- if the __mode field has both a lowercase k and a lowercase v then it will act as a table with weak keys and values
Which makes setting __mode as a string other than k, v or kv pointless. Not really relevant to know then. __mode as k makes keys weak, v for values and kv for both. Anything else is treated as a normal table. I was just confused on what __mode was for and what happens when the value of __mode changes, you answered that initially and that was enough.
Did you mean kv, or is uv something different? What is “U”? If U doesn’t mean anything and it only searches for the v, this isn’t really something that needs to be known either. Chances are if you need to use __mode then you’re going to use it properly and assign a proper value, not rely on it’s string search behaviour to determine what mode to use.