Page 3 of 3

Re: BulletManager (performance argument)

Posted: Sun Aug 28, 2016 7:06 pm
by raidho36
It's actually the index of any element preceding a nil
That appears to be the case. But then "length" is a bad name as well because array could be longer than this value. So the only way to reliably iterate through array with holes is to use "pairs". Then again, it ignores holes and includes literal indices. Alternatively, you keep track of its real length elsewhere.

Re: BulletManager (performance argument)

Posted: Sun Aug 28, 2016 7:44 pm
by pgimeno
airstruck wrote:No, it isn't. It's actually the index of any element preceding a nil (which may or may not be the highest numbered integer indexed element). The manual says so in the first sentence of the paragraph explaining the behavior of the length operator on tables.
In further support of this, in LuaJIT:

Code: Select all

print(#{1, 2, nil, 4, 5}) -- prints 5
print(#{1, 2, 3, nil, 5}) -- prints 3

Re: BulletManager (performance argument)

Posted: Sun Aug 28, 2016 7:59 pm
by airstruck
raidho36 wrote:But then "length" is a bad name as well because array could be longer than this value.
Bad or not, that's still its name. If you have a better suggestion for a name, pitch it to the Lua authors. It would be confusing if users started calling it by something other than its name.

Also, an array can't be longer than this value if "length" in this context simply means the index of any non-nil element preceding a nil, and nothing more. The word can mean whatever the authors want it to mean; they probably just found it to be a good fit for that concept (I've never seen any better suggestions, anyway).
So the only way to reliably iterate through array with holes is to use "pairs". Then again, it ignores holes and includes literal indices.
And the order of iteration is not defined, and it won't JIT.
Alternatively, you keep track of its real length elsewhere.
Yeah, that's the usual approach to storing sparse arrays. Generally the "real" length is stored in the same table in a key named "n" (which has some historical precedent because of its special meaning to the deprecated/removed "table.getn" and "table.setn" functions).
pgimeno wrote:In further support of this, in LuaJIT:

Code: Select all

print(#{1, 2, nil, 4, 5}) -- prints 5
print(#{1, 2, 3, nil, 5}) -- prints 3
Right, and it's implementation-dependent; as I recall PUC Lua gives different results in at least one of those cases. Anyway, bottom line is # won't give predictable results on sparse arrays.

Re: BulletManager (performance argument)

Posted: Sun Aug 28, 2016 8:12 pm
by raidho36
pgimeno wrote: In further support of this, in LuaJIT:

Code: Select all

print(#{1, 2, nil, 4, 5}) -- prints 5
print(#{1, 2, 3, nil, 5}) -- prints 3
Furthermore

Code: Select all

foo = {1, 2, 3}
print(#foo) -- prints 3
foo[10] = 10
print(#foo) --prints 3 also
Now that I think of it, I believe I have an idea why it works like this. In LUA, tables consist of two parts: array part and hash part. Small integer keys go to array part, everything else goes to hash part. When space runs out, it doubles part's length, and to avoid unnecessary reallocation early on its pre-heated to 4 elements each. If you add an integer key outside of array part size and it decides it's not worth to resize it to fit new key, it puts it to hash part. At the same time, removing keys in the middle of it doesn't alters it's length. So I believe, length operator only returns largest key from array part. It's obviously not possible (feasible anyway) with hash part. Hence length is not necessarily largest integer (it could be in hash). In fact I'm pretty sure you can construct a table with nothing but integer keys with length 0 by making it put them all in hash part.

Code: Select all

print (#{ [1000] = 1, [1010] = 2, [1020] = 3 }) --prints 0