Q: Lua global __newindex called only once Working through the Lua exercises in 7 More Languages in 7 Weeks and getting caught on a metatables problem.
The challenge is to overload the + operator in order to be able to concatenate tables (as though they were arrays).
{ 1, 2, 3 } + { 4, 5, 6 } -- { 1, 2, 3, 4, 5, 6 }

So I tried to use the __add metamethod and created a metatable to host it.
local mt = {
  __add = function(lhs, rhs)
    return concatenate(lhs, rhs)
  done
}

I mistakenly tried to set this metatable on the global table, but this obviously doesn't propagate down to all other tables.
In an attempt to add it to all created tables, I created a separate metatable on _G which would use the __newindex metamethod, then set the original metatable every __newindex was activated.
setmetatable(_G, {
  __newindex = function(array, index)
    setmetatable(array, mt)
  end
})

However, this didn't work:
a1 = { 1, 2, 3 }
a2 = { 4, 5, 6 }
a1 + a2

And resulted in the following error: attempt to perform arithmetic on global 'a1' (a nil value)
So I threw a print statement into the global metatable to see whether it was actually being called:
setmetatable(_G, {
  __newindex = function(array, index)
    print('new table ' .. index)
    setmetatable(array, mt)
  end
})

This only ever prints the first table to be created:
a1 = { 1, 2, 3 }
a2 = { 4, 5, 6 }
a3 = { 4, 5, 6 }
a4 = { 4, 5, 6 }

Results in:
new table a1

I expect I am accidentally overriding something, because when I remove the call to setmetatable
setmetatable(_G, {
  __newindex = function(array, index)
    print('new table ' .. index)
    --setmetatable(array, mt)
  end
})

It prints all entries as expected.

A: setmetatable(_G, {
    __newindex = function(array, index)
        print('new table ' .. index)
        setmetatable(array, mt)
    end
})

When you do a1 = { 1, 2, 3 } then __newindex is going to be called with with array being _G and index being 'a1'. Then calling setmetatable(array, mt) is going to change the metatable of _G, undoing the effect of the original setmetatable call.
You probably want something more like:
setmetatable(_G, {
    __newindex = function(array, index)
        setmetatable(array[index], mt)
    end
})

But there's another problem because now the original effect of the assignment no longer takes place. __newindex is called instead, so a1 remains a nil value.
You could try array[index] = value within the __newindex function but this will call the same __newindex again. Instead, use rawset:
setmetatable(_G, {
  __newindex = function(array, index, value)
    rawset(array, index, value)
    setmetatable(array[index], mt)
  end
})

Note that __newindex takes 3 parameters.
Now, what happens when you assign a non-table to a global like b = 1?
