apiluamanual

Meaning of "Lua does not perform the primitive assignment." in 2.4 (concerning __newindex)


from https://www.lua.org/manual/5.3/manual.html see section 2.4. Concerning the metamethod operation __newindex states the following quote:

__newindex: The indexing assignment table[key] = value. Like the index event, this event happens when table is not a table or when key is not present in table. The metamethod is looked up in table.

Like with indexing, the metamethod for this event can be either a function or a table. If it is a function, it is called with table, key, and value as arguments. If it is a table, Lua does an indexing assignment to this table with the same key and value. (This assignment is regular, not raw, and therefore can trigger another metamethod.)

Whenever there is a __newindex metamethod, Lua does not perform the primitive assignment. (If necessary, the metamethod itself can call rawset to do the assignment.)

of that I ask what the follow specifically intends to say

"Lua does not perform the primitive assignment. (If necessary, the metamethod itself can call rawset to do the assignment.)"

Does this mean that if the value is a number, which is a primitive, it will not be assigned to the provided table through the metamethod event and we have to use rawget or something? This is very confusing and contradictory to me.


Solution

  • I want to show same examples to help you figure out this confusion. The primitive assignment example:

    local test = {}
    test['x'] = 1 -- equal to rawset(test, 'x', 1)
    print(test['x']) -- 1
    print(rawget(test,'x')) -- 1
    

    the primitive assignment code test['x'] = 1 equal to rawset(test, 'x', 1) when the table test have no __newindexmetamethod.

    then the __newindex metamethod example:

    local test = {}
    setmetatable(test, {__newindex = function(t,key,value) end})
    test['x'] = 1
    print(test['x']) -- nil
    print(rawget(test,'x')) -- nil
    

    the assignment test['x'] = 1 will trigger to call the __newindex function. if __newindex do nothing, then nothing happens, we will get nil result of test['x'].

    If the __newindex function call rawset:

    local test = {}
    setmetatable(test, {
      __newindex = function(t,key,value) 
                     rawset(t,key,value) -- t:test key:'x' value:1
                   end})
    test['x'] = 1
    print(test['x']) -- 1
    print(rawget(test,'x')) -- 1
    

    the code have same effect as the first example. So the manual say:

    "Lua does not perform the primitive assignment. (If necessary, the metamethod itself can call rawset to do the assignment.)"

    Then the problem is, how we can use __newindex? It can be used to separate the old and new index in table.

    local test = {y = 1}
    local newtest = {}
    setmetatable(test, {
        __newindex = 
            function(t,key,value)
                newtest[key] = value
            end,
        __index = newtest
    })
    
    test["x"] = 1
    
    print(test['x']) -- 1
    print(test['y']) -- 1
    
    print(rawget(test, 'x')) -- nil
    print(rawget(test, 'y')) -- 1
    

    the old index 'x' and new index 'y' can all be accessed by test[key], and can be separated by rawget(test, key)