Log In  

The following behavior is consistent with Lua 5.1 so I don't want to call this a bug (better to match the official interpreter than diverge), but it's a gotcha that affects Pico-8 programmers and might justify adding in support for more Lua keywords. In short, #t is inconsistent after some table operations.

function p(t)
  for k,v in pairs(x) do
    print(k..': '..v)

x = {1, 3, 5, 7}
p(x)  -- 1: 1, 2: 3, 3: 5, 4: 7  (ok)
print(#x)  -- 4  (ok)

x[2] = nil
p(x)  -- 1: 1, 3: 5, 4: 7  (undocumented: pairs() skips nil values)
print(#x)  -- 4  (ok, though larger than the number of values returned by pairs())

x[4] = nil
p(x)  -- 1: 1, 3: 5  (consistent)
print(#x)  -- 1  (wat)
P#21563 2016-05-28 18:21 ( Edited 2016-05-28 23:16)

pairs just goes through every key in the table, doesn't care about what numerical keys there are.

Somewhat technical, but the way that length works is that Lua makes an array (Yes I mean array) to store those four numbers

When getting the length of it, it'll check if the top is nil or not, and in your first two examples it's not, so it'll okay, top is fine, length must be 4.

In the third example the top's been removed, so it starts searching for the highest power of two that doesn't exist, 1, 2, 4, 8, etc. It'll stop at 2 because that was removed in the second example, then backtrack until it finds something valid and return that. hence 1

You may find that a bit odd of behaviour, but if you look in the manual: "the length of a table t is only defined if the table is a sequence", tables that are full of holes like in that example are subject to the defined but not-documented-in-manual behaviour of binary searching, which I guess could change if they so desired to.

P#21564 2016-05-28 18:58 ( Edited 2016-05-28 23:00)

The way the # length operator works in Lua is kind of weird and can trip people up a bit, but I think it kind of makes sense considering their weird decision to mix dictionaries and arrays under one data structure.

Setting a value to nil is essentially how you remove elements from an table. So this is why pairs will skip nil values -- the keys are no longer held by the table.

However, removing keys will create "holes" in the middle of tables if they're used as a sequence. If you're deleting elements, sometimes you can use pico8's del function, which it deletes by finding a value rather than just letting you specify an index, but that occasionally has problems if you have duplicates of the same value in your table.

I think pico8 could benefit from a builtin remove by index function for this usage which is like table.remove in proper Lua.

But for now, if del doesn't work for you, you can do removal manually: shift elements down one-by-one, and then set t[#t] = nil.

The Lua 5.2 manual pretty much just says if you try to use the # operator on a normal table that isn't a "sequence" (where indexes 1..n have non-nil values), then all bets are off. In the Lua 5.1 manual, they said that it could be ANY index that was directly before a nil value.

From what I can gather # was decided to be a binary search for an entry beside a nil value, rather than a linear search for the max integer index in the table. This way it could be faster to find the length on normal array-like tables, but it definitely comes with some annoying quirks if you blow a hole in your table by accident.

Normal Lua made it easier to avoid because it encouraged you to use the table library when you used tables like arrays: table.insert to add values, and table.remove to remove values. pico8's del doesn't work if there are duplicates since it always deletes the first match.

(sorry that became way more rambly than intended heh.)

P#21570 2016-05-28 19:11 ( Edited 2016-05-28 23:34)

Great answers, both. Thanks! It's a bit odd but if it's well understood by the Lua community at large then I'm not inclined to suggest changes, other than Pico-8 adopting Lua features that accommodate uses cases otherwise not well supported.

P#21571 2016-05-28 19:16 ( Edited 2016-05-28 23:16)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2022-11-30 08:02:12 | 0.006s | Q:11