Hello!

I have just started to dive into Pico 8 and Lua. I've been working on building a simple animator for my game and have run into some strange issues with regard to tables.

I declare a table and later add to it like this:

a = {} a.p = {x=1, y=2, z=3} |

The function count(a) then returns 0. Additionally, all(a) and foreach(a, function) will not iterate overt the table. Strangely, I am still able to access the information. For example,

print(a.p.x) |

will correctly print the number 1. If I declare the table explicitly

a = {p={x=1,y=2,z=3}} |

I have no issues. I also don't have issues if I use add() to insert new table values. However, I need to utilize the associative array functionality of the table and to add and remove values at runtime, so neither of these solutions is sufficient.

The best fix I have found is to use pairs() instead of all(). For some reason, pairs() works properly regardless of how I add values to the table. This solves my problem, but the fact that I have no idea why leads me to believe that I have some serious misunderstanding of how Lua tables and/or the Pico 8 tables api works. I'm curious as to whether others have encountered this issue and would appreciate some feedback as to where my misunderstanding may lie.

A number of functions that work on tables operate on consecutive numeric indices starting at 1. So a loop over all(tbl), for instance, will run on tbl[1], tbl[2], tbl[3], and so on until it encounters one that isn't defined. It won't skip missing numbers, so if tbl has keys 1, 2, 3, and 7, it'll only get the first three.

As an aside, I'm pretty sure count() is deprecated.

It's literally a function roughly like this, hidden behind the scenes:

function count(t) local i=0 repeat i=i+1 until t[i]==nil return i-1 end |

It's not exactly performant or robust.

If you want the count of a numerically-indexed array, use the # operator, which is fast, or if you want to count the elements of an arbitrarily-mapped table, use pairs() and count them yourself:

function tablesize(t) local c=0 for k,v in pairs(t) do c+=1 end return c end |

Thank you! I did not realize that the implementation of add() and all() rely on a sequence table, but that makes quite a bit of sense. Out of curiosity, how does the # operator work? I have been treating # and count() as interchangeable, and it seems that # relies on a sequence as well.

The operator **#** works by returning **0** if **t[1]==nil**, or by searching for an integer **n** such that **t[n]!=nil** and **t[n+1]==nil**.

If the integer indices in your table are continuous and start at 1, this will return the length of the array part. Otherwise, this *may* return the length of the array, but you will have surprises.

Not exactly. The # operator returns a cached value for the sake of speed. Lua tries to keep it correct by recognizing things that would make it change, but you can definitely set up an array from 1 to 100 and then set array[50] to nil and #array will still say 100.

Here:

Sometimes it'll get it right if you set a bunch to nil, but not always. The only guaranteed change is when you set a[#a] to nil.

Mostly you should consider the # operator to return the index of the highest-known non-nil entry.

Yep, the manual says this:

"When t is a sequence, #t returns its only border, which corresponds to the intuitive notion of the length of the sequence. When t is not a sequence, #t can return any of its borders. (The exact one depends on details of the internal representation of the table, which in turn can depend on how the table was populated and the memory addresses of its non-numeric keys.)"

A "border" here is what's been mentioned earlier in the thread: A non-nil value followed by a nil value.

I basically tread # as "undefined" for non-sequences.

@Felice maybe you misread me? I said Lua finds **an** integer that satisfies the property (any integer it deems suitable, and 100 satisfies the property in your example). And **if** the array is well-formed, then it returns the size of the array.

[Please log in to post a comment]