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).