Reputation: 13
Lua has a piece of syntactic sugar that allows for OOP methods to be implemented: the operator :
when used as foo:bar(biz)
is equivalent to foo.bar(foo,biz)
. However, what I've noticed is that it is also actively used by the standard string library in this manner:
local a = "a normal string"
local b = a:reverse() -- ????????
print(b)
-- outputs: gnirts lamron a
The question is: how exactly is this achieved? Naturally, when you try to assume that it expands to a.reverse(a)
it falls apart, as a
is a string and cannot possibly contain the key reverse
, moreover, the statement is actually equivalent to string.reverse(a)
. My hunch was that it actually expands to _G[type(a)].reverse(a)
, but then you remember that the same stuff happens in the io
library on file descriptors...
Upvotes: 1
Views: 495
Reputation: 2793
Every string in Lua (5.1 - 5.4) has a metatable with metamethod __index.
Thats the place where all string functions are present.
Here is a function that shows it...
-- help()
help=function(help)
dump(debug.getmetatable(help).__index)
end
Thats very simple, isnt it?
EDIT: Because i forget the dump function :-) ...
-- dump(table)
dump=function(...)
local args={...}
local test,dump=pcall(assert,args[1])
if test then
for key,value in pairs(dump) do
io.write(string.format("%s=%s\n",key,value))
io.flush()
end
return true
else
return test,dump
end
end
Theres a string called _VERSION - Lets have a look on it...
>help(_VERSION)
reverse = function: 0x565c4870
lower = function: 0x565c4ab0
sub = function: 0x565c7020
byte = function: 0x565c6d30
gsub = function: 0x565c7bb0
char = function: 0x565c4d80
format = function: 0x565c5060
unpack = function: 0x565c62d0
gmatch = function: 0x565c6ee0
dump = function: 0x565c5a90
upper = function: 0x565c47e0
find = function: 0x565c7ba0
len = function: 0x565c44d0
rep = function: 0x565c4900
pack = function: 0x565c66e0
packsize = function: 0x565c61c0
match = function: 0x565c7b90
Thats the reason why it works as methods with .
and :
Upvotes: 1
Reputation: 72271
The colon syntax really is equivalent to the dot syntax plus self parameter. So the question is, how does a.reverse
work?
The string library provides all its functions inside the table
string
. It also sets a metatable for strings where the__index
field points to thestring
table. Therefore, you can use the string functions in object-oriented style. For instance,string.byte(s,i)
can be written ass:byte(i)
.
We can see these metatable details with the code:
local a = "a normal string"
strindex = getmetatable(a).__index
if type(strindex) == "table" then
print "string has metatable entry __index:"
for k,v in pairs(strindex) do
local same = (v == string[k])
print(k, type(v), "same as string."..k..":", same)
end
end
local b = a.reverse(a) -- ????????
print(b)
-- outputs: gnirts lamron a
Try it online!: the output is
string has metatable entry __index:
rep function same as string.rep: true
byte function same as string.byte: true
sub function same as string.sub: true
char function same as string.char: true
gmatch function same as string.gmatch: true
format function same as string.format: true
reverse function same as string.reverse: true
match function same as string.match: true
dump function same as string.dump: true
len function same as string.len: true
packsize function same as string.packsize: true
find function same as string.find: true
unpack function same as string.unpack: true
upper function same as string.upper: true
pack function same as string.pack: true
lower function same as string.lower: true
gsub function same as string.gsub: true
gnirts lamron a
Upvotes: 2