Proper way to make a .new() function in a modulescript

I’m trying to figure out how to make a module with a proper .new() function. Currently I have

local Vector4 = {}
Vector4.mt = {}

Vector4.new = function (self, inputVec)
    self.v = inputVec
    return self
end

Vector4.mt.__tostring = function (self)
    return string.format("(%d, %d, %d, %d)", self.v[1], self.v[2], self.v[3], self.v[4])
end

setmetatable(Vector4, Vector4.mt)
return Vector4

This does not work. Running

local Vector4 = require(script.Vector4)
local a = Vector4:new({1, 2, 3, 4})
local b = Vector4:new({5, 6, 7, 8})
print(a)
print(b)

Reveals that both a and be have become (5, 6, 7, 8)! How do I fix this?

When making a .new() function it should be what creates the table. It’s making a new table. And then it returns that table.

Vector4.new = function (inputVec)
    local self = {}
    setmetatable(self,Vector4.mt)
    self.v = inputVec
    return self
end

You will never be using a .new() function which needs to get self because there is no table for it to reference.

Also you can try simplifying

local Vector4 = {}
Vector4.__index = Vector4

function Vector4.new(inputVec)
	...
	return setmetatable(self, Vector4)
end
1 Like

This is not how metatables work. Metatables is an extension of a table that gives you useful functions. The correct way to execute your code would be something along the lines of…

local Vector4 = {}
Vector4.__index = Vector4

function Vector4.new(inputVector)
    local self = {
        v = inputVector
    }
    
    setmetatable(self, Vector4)
    
    return self
end

--Add your __tostring metatable

return Vector4

I’d recommend visiting this post for a better understanding of metatables.

1 Like

There is a bug in your code snippet

Here, you are setting the metatable to self to be Vector4, yet you are returning Vector4,

I think you meant

return setmetatable(self, Vector4)

My bad. Thanks for letting me know.