What's the difference between : and . in OOP?

Hey everyone,

I’ve lately been running into programmers using different operators when writing code in module scripts. The most common is : and . but I’ve also seen some use of :__ and .__. I’m unsure what the difference is between using any of these in module scripts.

I’ve heard some talk about how using a different operator changes how your code is run but I’ve never been able to verify that.

I’m aware that : allows you to access self but I’m not sure what the __ means after that.

Does anyone know what the difference is?

Function example:

function Module:FunctionName()

end

function Module.FunctionName()

end
1 Like

Functions with the “:” operation can access “self” while the latter cannot.

I’m aware that : allows you to access self but I’m not sure what the __ means after that.

someVariable:someFunction() behaves the exact same as someVariable.someFunction(someVariable). It implicitly passes itself as the first argument. This is useful when using lua OOP as you would want to modify the object directly instead of having to continually pas it into a function.

In this specific example you shared, the first function you posted would have 1 argument, where the first argument is self, same as with calling them.

1 Like

Typically, people will use __ so the method is treated as a metamethod if the table it is in is used as a metatable. An example would be making a class with custom index behavior.

Example:

-- Typical class implementation:
local Class = {}
Class.__index = Class

function Class.new()
    return setmetatable({}, Class)
end

-- Special class implementation that utilizes a metamethod with the : notation.
local Number = {}

-- use index as a true metamethod instead of the shorthand to point at another table
-- note the first arg if using .__index is the table the metamethod is working with, thus why the : gives us a valid self variable
function Number:__index(key) 
    if key == "inverse" then -- Do an operation for a specific key
        return 1 / self.n
    else
        return Number[key] -- Otherwise default to looking up in the original table
    end
end

function Number.new(n: Number)
    local self = setmetatable({}, Number)
    self.n = n

    return self
end

local number = Number.new(10)
print(number.inverse) --> should output something like 0.1

There are a lot of other usecases with other metamethods.
Additionally, others and myself also will use underscores to signify that something is intended to be used privately (not accessed from outside the class) but I usually only use one underscore to denote that.

3 Likes