If you make your own plugin you are mostly interested in module scripts, but the most interesting are the classes, for example the Vector3 class, or the Instance class and so on. These are very well structured and readable, but only if you do them well. I have looked at some of them at Egomoose on Github (Example of a Vector2 class), but I still don’t understand much about them. So I ask here: How can I write a good, readable class?
You’re looking for object orientated programming.
@Ukendio Yes, and I already know the basic syntax, but there are things I don’t understand, for example:
function mt.__index(v3, k)
local props = ref[v3];
local k = lower(sub(k, 1, 1)) .. sub(k, 2);
if (k == "unit") then
local x, y, z = props.x, props.y, props.z;
local m = 1 / props.magnitude;
return vector3.new(x*m, y*m, z*m);
elseif (props[k]) then
return props[k];
elseif (vector3[k]) then
return vector3[k];
else
error(k .. " is not a valid member of Vector3");
end
end
function mt.__newindex(v3, k, v)
error(k .. " cannot be assigned to");
end
function mt.__eq(a, b)
if (not not ref[a] and not not ref[b]) then
local a, b = ref[a], ref[b];
return a.x == b.x and a.y == b.y and a.z == b.z;
else
return false;
end
end
function mt.__unm(v3)
local props = ref[v3];
return vector3.new(-props.x, -props.y, -props.z);
end
function mt.__add(a, b)
if (not not ref[a] and not not ref[b]) then
local a, b = ref[a], ref[b];
return vector3.new(a.x + b.x, a.y + b.y, a.z + b.z);
elseif (not not ref[a]) then
error("bad argument #2 to '?' (Vector3 expected, got " .. typeof(b) .. ")")
elseif (not not ref[a]) then
error("bad argument #1 to '?' (Vector3 expected, got " .. typeof(a) .. ")")
end
end
function mt.__sub(a, b)
if (not not ref[a] and not not ref[b]) then
local a, b = ref[a], ref[b];
return vector3.new(a.x - b.x, a.y - b.y, a.z - b.z);
elseif (not not ref[a]) then
error("bad argument #2 to '?' (Vector3 expected, got " .. typeof(b) .. ")")
elseif (not not ref[a]) then
error("bad argument #1 to '?' (Vector3 expected, got " .. typeof(a) .. ")")
end
end
function mt.__mul(a, b)
if (not not ref[a] and not not ref[b]) then
local a, b = ref[a], ref[b];
return vector3.new(a.x * b.x, a.y * b.y, a.z * b.z);
elseif (not not ref[a] and typeof(b) == "number") then
local a = ref[a];
return vector3.new(a.x * b, a.y * b, a.z * b);
elseif (not not ref[b] and typeof(a) == "number") then
local b = ref[b];
return vector3.new(a * b.x, a * b.y, a * b.z);
else
error("attempt to multiply a Vector3 with an incompatible value type or nil")
end
end
function mt.__div(a, b)
if (not not ref[a] and not not ref[b]) then
local a, b = ref[a], ref[b];
return vector3.new(a.x / b.x, a.y / b.y, a.z / b.z);
elseif (not not ref[a] and typeof(b) == "number") then
local a = ref[a];
return vector3.new(a.x / b, a.y / b, a.z / b);
elseif (not not ref[b] and typeof(a) == "number") then
local b = ref[b];
return vector3.new(a / b.x, a / b.y, a / b.z);
else
error("attempt to divide a Vector3 with an incompatible value type or nil")
end
end
function mt.__tostring(v3)
local prop = ref[v3];
return format(rep("%s, ", 2) .. "%s", prop.x, prop.y, prop.z);
end
I know this are methamethods, but i dont know why @EgoMoose use it.
The meta methods are what allow you to use, say, a * b , instead of having to do a:Multiply(b). So when the user writes a * b with your class, the.__mult(a,b) function is called.
The lua wiki explains these in further detail: lua-users wiki: Metamethods Tutorial
@madattak But I can also change the name of mt, or (I know how OOP works, I’m just afraid that the name has to be mt) Then I only have two questions: 1. What the methamethod __type
does do in this case? 2. What the methamethod __mode
does do in this case?
mt can be replaced with whatever you want, it’s just a name, presumably short for metatable, as long as its the same as the name you gave to the metatable. Most of the methods can be seen here:
I assume type controls what happens when you use type(a), but not sure.
Mode is used for weak tables
https://www.lua.org/pil/17.html
(tl;dr objects held only by a weak table and nothing else will not be considered ‘in use’ by lua and garbage colected (erased and forgotten))
@madattak Why and when should I use weak values? What do I gain if I use them? The link did not help me there.
I think it’s basically for very rare cases when you need a table full of objects (Not Roblox Instances like parts though!) and need them to be cleared out of memory without removing them from the table yourself. I’ve never needed to use them though, so someone else would probably be able to provide a better answer!
@madattak, sorry if i relive this topic (and if i am annoying you), but i just realized that i not understand why Egomoose use the ref table. It would be simpler by use the vector2 class self, or not?