Changing metatable in Lua breaks colon operator

758 Views Asked by At

While learning Lua, I borrowed some code from here to use string indexing, which is exactly this:

getmetatable("").__index = function(str, i) return string.sub(str, i, i) end

After that, I wrote a function to reverse a string as practice.

function reverse_string(str)
    local s = ""
    for i = string.len(str), 1, -1 do s = s .. str[i] end
    return s
end

That works fine, until I change the string.len(str) to str:len(), then I get this error:

reverse.lua:9: bad argument #2 to 'sub' (number expected, got string)

Debugging print()'s tell me that the __index function is being called on str:len(), and that the i argument is becoming the string "len". I know that str:len() works without the metatable there, but as soon as I add it this happens, why?

2

There are 2 best solutions below

1
On BEST ANSWER

From Lua 5.2 Refernce Manual:String Manipulation

The string library provides all its functions inside the table string. It also sets a metatable for strings where the __index field points to the string table. Therefore, you can use the string functions in object-oriented style. For instance, string.byte(s,i) can be written as s:byte(i).

So, the object oriented style like str:len() comes from the default metamethod __index, which you have modified.

0
On

The index function is passed the table, and the key that is being indexed. so 'str' should be the string and 'i' should be key in your case. Because "len" is not in the meta table it calls __index and passes the string as the first argument and the key ("len") as the second argument. it looks as though you need to check to the type of 'i' to see what to do for better handling of strings

getmetatable("").__index = function(str, key)
  if type(key) == "string" then
    return string[key]
  else
    return string.sub(str, key, key)
  end
end

str = "hello, world!"
print(str:len())
print(str[5])

see here for more info