1

I'm writing a "C" userdata array structure. As setter and getter i want normal array access (u[0] = 1 u[0]) like it's discussed here: [c array share][1]Share Array between lua and C. For that i need to set __index and __newindex to the set and get functions in c.

Additional i want object-oriented access, too, "like u:mymethod()". My trouble is, that i need to set now __index to the metatable itself.

Is there a way, to achieve both?

Community
  • 1
  • 1
user2328978
  • 55
  • 1
  • 5

1 Answers1

4

Just one of many possible ways to achieve this:

local userdata = { _array = { "A", "B", "C" } }
local mt = { }
local methods = { }

function mt.__index(userdata, k)
    if methods[k] then
        return methods[k]
    else
        return rawget(userdata, "_array")[k]
    end
end

function mt.__newindex(userdata, k, v)
    if methods[k] then
        error "can't assign to method!"
    else
        rawget(userdata, "_array")[k] = v
    end
end

function methods.count(userdata)
    return #rawget(userdata, "_array")
end

setmetatable(userdata, mt)

userdata[3] = "Z"

print(userdata[1])
print(userdata[2])
print(userdata[3])
print(userdata:count())

userdata.count = 0

edit: As lhf pointed in his comment, it is not dangerous to use metatable as it's __index table at all, because c-methods should always check on what self they operate.

  • Uisng the metatable as `__index` is not dangerous per se. I do it all the time. You only have to take a bit of care in metamethods to make sure you get userdata of the correct type. But you have to do it anyway, because one can always call `getmetatable(u).__gc(u)` unless you protect the metatable. – lhf May 02 '13 at 01:26
  • Oh, glad to meet you, Mr. de Figueiredo! I absolutely forgot that luaL_checkudata() protects us from such errors. I'll edit my answer accordingly. Thank you for this great project, sir! –  May 02 '13 at 13:44