• Subject: Re: A tricky way to determine Lua version (updated)
• From: Philippe Verdy <verdyp@...>
• Date: Wed, 22 Jul 2020 05:19:26 +0200

if ({false, [1] = true})[1] then
return 'LuaJIT'

I'm not sure that the evaluation of the table constructor is documented correctly. Here you assign two different boolean values to the same index [1], this creates a collision and the evaluation order matters.

And there should be no difference with
if ({[1] = false, [1] = true})[1] then
return 'LuaJIT'
even if the first index is given explicitly.

In my opinion the constructor should always be storing values in the table in the order indicated, but this is unspecified (note that the values assign to each index should all be evaluated at run time, even if they are colliding when storing them at a given index position, as well all specified index should be evaluated) as if the constructor was in fact using a pair of sequences of equal length:
__constructor(__keys, __values)
with __keys= {1, 1} and __values = {false, true)

So make this test:
local function ident(x) print("ident: "..tostring(x)); return x; end
k = {ident(1), ident(1), ident(2)}
v = {ident(false), ident(true), ident('other'}
t = {k[1] = v[1], k[2] = v[2], k[3] = v[3]}
and you should see six calls:
ident:1
ident:1
ident:2
ident: false
ident: true
ident: other
and t should still contain a two keys at [1] and [2] (not 3), and the value t[1] should be v[2] == true, not v[1] = false which was first assigned but then reassigned/overwritten in t[k[2]] == t[1] == t[k[1]]

How can LuaJIT behave differently ??? This does not seem coherent. May be it was specified now, but being unspecified in the past means that the test is not really conclusive about what was the "correct" behavior in past versions.

Is the order of evaluation of table constructors really specified now (i.e. the order of evaluation of keys expressions, and values expressions, and then the order of assignment) ?

And are all these evaluations interleaved (i.e. evaluate the first key, then the first value, then assign, then restart with the next key/value pair) or separated (all keys first, then all values, then all assignments)?

Or mixed: i.e. keys and values evaluation interleaved, and stored in a single temporary sequence (then used to create the constructor)? As if the code for
t = {ident(1) = ident(false), ident(2) = ident(true), ident(3) = ident('other')}
was:
__kv= {ident(1), ident(false), ident(2), ident(true), ident(3), ident('other')}
t = __convertkeyvalues(__kv)
which should also print:
ident:1
ident:1
ident:2
ident: false
ident: true
ident: other
in that order, for the evaluation of each key and value before the actual storage in the final array, and that would also assign values in t in the ascending sequence in _kv (the last keys overwriting the value used in any prior key).

The Lua Documentation is not very specific (unlike in expressions for the evaluation of binary and unary operators and their associativity). If this is unspecified, the result in Lua is also unpredictable.