Keeping a list of known fields

Posted by David Haley on Sat 06 Sep 2008 03:52 AM — 3 posts, 12,143 views.

USA #0
I have an object, the details of which aren't really important (it's a binding for characters), represented by a table in Lua-space. This object has many fields. Lua has no compile-time checking for whether or not a field exists, so there is no way for me to know if I made a typo when I access a field in the code. The best I can do, if I want to be sure that I'm accessing a field that's actually valid, is to have runtime checks against a list of known fields. Currently I'm doing this:

local priv_fields = 
    set.new({
        "inputStatus", "inputCoroutine", "inputCommand",
        "sendPrompt",
    })

function __index(actor, key)
    -- is this a known field?
    if priv_fields:contains(key) then
        return actor.__private[key]
    end

    -- is it a module field?
    if _M[key] then
        return _M[key]
    end

    -- we don't know what it is... ack
    error("unknown actor field/method: " .. key)
end

function __newindex(actor, key, val)
    -- if it's a known field, we can set it
    if priv_fields:member(key) then
        actor.__private[key] = val
        return
    end

    -- can't assign to anything else...
    error("can't assign to actor field: " .. key)
end


Every access to a field entails the indirection of the metatable. Admittedly, this is not very expensive: at worse it is just two table lookups. (Well, set:contains entails a function call that then does a table lookup. So that's two table lookups and a function call.)

Is this a reasonable solution? What are other people doing? Not having any kind of compile-time verification kind of bothers me, and implementing (or finding/figuring out somebody else's) static analysis is not something I really have time to do. I'm not happy with the runtime checks (their usefulness is directly proportional to the code's frequency of execution) but it's the best I'm seeing at the moment.
Australia Forum Administrator #1
Can't you just use __index without the hidden table? That way, an attempt to get a non-existent field will involve the check, but if the field has data in it, you assume it is good.
USA #2
Do you mean only use __newindex? I want an error to be triggered when an unknown is either accessed or created. Doesn't that mean I need to use both?

Or did you mean that __index can see directly if the field exists in the actor? Something like this:


function __index(actor, key)
    -- is this a known field?
    if actor[key] then
        return actor.__private[key]
    end

    -- is it a module field?
    if _M[key] then
        return _M[key]
    end

    -- we don't know what it is... ack
    error("unknown actor field/method: " .. key)
end


The problem here is that some fields might legitimately be nil-valued, but still be known fields. How would you get around that?