# Creating 2D vectors

I've made a little mechanism for creating 2-D vectors in Lua. Vectors have two components i and j, and support addition, dot product, magnitude, and conversion to strings.

Vector = {
new = function (i, j)
return setmetatable({i = i, j = j}, {
__index = Vector,
return Vector.new(self.i + v.i, self.j + v.j)
end,
__mul = function (self, v)
return self.i*v.i + self.j*v.j
end,
__tostring = function (self)
return string.format('<%g,%g>', self.i, self.j)
end
})
end,
magnitude = function (self)
return math.sqrt(self.i*self.i + self.j*self.j)
end
}

u = Vector.new(3, 4)
v = Vector.new(-5, 10)
print(u.i)
print(u.j)
print(u:magnitude())
print(u + v)
print(u * v)


While I get expected results, I don't like the fact that each time I create a vector table, a brand new metatable is created. It would be nice to only have one metatable for all vectors. Also if there any non-idiomatic aspects to the code, those would be nice to know about as well.

• I'm not a Lua expert but wouldn't defining a separate metatable and then using setmetatable accomplish what you want? Mar 11, 2015 at 15:59
• Yes but it would nice to actually hide the metatable so it is not globally available. Mar 11, 2015 at 20:17

I would recommend creating a separate module/package for the Vector types.

1. Create a file named vector.lua. It'll return the custom Vector data structure.
2. Use a local do...end block to wrap your meta-table. This will make the meta table private.
3. magnitude is basically square-root of the result from self * self. Use this. ;-)
4. I prefer to use __call meta-method instead of writing a new .new call. This is of course a personal preference.

The resulting vector.lua would be like:

local Vector = {}
do
local meta = {
_metatable = "Private metatable",
_DESCRIPTION = "Vectors in 2D"
}

meta.__index = meta

return Vector(self.i + v.i, self.j + v.j)
end

function meta:__mul( v )
return self.i * v.i + self.j * v.j
end

function meta:__tostring()
return ("<%g, %g>"):format(self.i, self.j)
end

function meta:magnitude()
return math.sqrt( self * self )
end

setmetatable( Vector, {
__call = function( V, i ,j ) return setmetatable( {i = i, j = j}, meta ) end
} )
end

Vector.__index = Vector

return Vector


Now, to use it as a package, just put a require call:

local Vector = require 'vector'
u = Vector(3, 4)
v = Vector(-5, 10)

• Excellent advice. __call was new to me. It looks more idiomatic than new. Oct 11, 2015 at 18:53