Reputation: 189876
I am confused about the difference between function calls via .
and via :
local x = {
foo = function(a, b) return a end,
bar = function(a,b) return b end
}
return x.foo(3, 4) -- 3
return x.bar(3, 4) -- 4
return x:foo(3, 4) -- table: 0x10a120
return x:bar(3, 4) -- 3
What is the :
doing?
Upvotes: 259
Views: 76753
Reputation: 29234
It's syntactic sugar:
Here shows defining the function each way, and calling each of those both ways:
obj = {name = "alice"}
function obj.Greet(self, greeting)
print(greeting..", "..self.name)
end
obj.Greet(obj, "hello")
obj:Greet("hello")
function obj:Thank(message) -- implied 'self' parameter
print(message..", "..self.name)
end
obj.Thank(obj, "thank you")
obj:Thank("thank you")
Upvotes: 1
Reputation: 22481
For definition it is exactly the same as specifying self manually - it will even produce same bytecode on compilation. I.e. function object:method(arg1, arg2)
is same as function object.method(self, arg1, arg2)
.
On use :
is almost the same as .
- a special kind of call will be used internally to make sure object
and any possible side-effects of calculations/access are calculated only once. Calling object:method(arg1, arg2)
is otherwise same as object.method(object, arg1, arg2)
.
Upvotes: 51
Reputation: 7064
To be completely precise, obj:method(1, 2, 3)
is the same as
do
local _obj = obj
_obj.method(_obj, 1, 2, 3)
end
Why the local variable? Because, as many have pointed out, obj:method()
only indexes _ENV
once to get obj
. This normally just important when considering speed, but consider this situation:
local tab do
local obj_local = { method = function(self, n) print n end }
tab = setmetatable({}, {__index = function(idx)
print "Accessing "..idx
if idx=="obj" then return obj_local end
end})
end
tab.obj.method(tab.obj, 20)
--> Accessing obj
--> Accessing obj
--> 20
tab.obj:method(10)
--> Accessing obj
--> 10
Now imagine the __index
metamethod did more than just printing something. Imagine it increased a counter, logged something to a file or deleted a random user from your database. There's a big difference between doing that twice or only once. In this case, there's a clear difference between obj.method(obj, etc)
and obj:method(etc)
.
Upvotes: 42
Reputation: 265100
The colon is for implementing methods that pass self
as the first parameter. So x:bar(3,4)
should be the same as x.bar(x,3,4)
.
Upvotes: 369