Page 1 of 1

pairs() vs next() with userdata objects?

Posted: Fri May 10, 2019 6:07 pm
by eradicator
So, for some time now i've been testing if i can use next instead of pairs, because i find it looks syntactically more pleasing (yes, i know there is no performance benefit). But yesterday i noticed something strange.

Take these two examples:

Code: Select all

/c for k,v in pairs(game.players) do print(v.name) end
This works fine.

Code: Select all

/c for k,v in next, game.players do game.print(v.name) end
This throws an "attempted to index userdata" error.

Upon further investigation i noticed that while pairs returns the expected table wrapper {__self=<userdata>}, next returns the <userdata> object without the table around it.

So my question is: Is this a bug? Am i just doing something stupid? Why does next work for normal tables but not for factorio rich objects?

Any help is appreciated.

Re: pairs() vs next() with userdata objects?

Posted: Fri May 10, 2019 6:27 pm
by eduran
Your issue is not about <userdata> objects, but about custom tables. Those can only be iterated over with the modified pairs() function Factorio provides. Retry your second example with something that returns a normal lua table of objects (e.g. game.get_train_stops()) and it will work.

Re: pairs() vs next() with userdata objects?

Posted: Fri May 10, 2019 6:53 pm
by eradicator
The API doc calls both game.players and game.get_train_stops's return value an "array of X" though, so i wouldn't know what kind of table to expect even if i did know where it came from, which i don't. Hrmpf. Guess i'll be converting all the next's back to pairs, what a pity.

Thanks alot for the hint though, totally forgot about custom tables special behavior.

Re: pairs() vs next() with userdata objects?

Posted: Fri May 10, 2019 6:55 pm
by Bilka
game.players says "custom dictionary uint or string", the "custom dictionary" part means that it is a LuaCustomTable.

Re: pairs() vs next() with userdata objects?

Posted: Fri May 10, 2019 7:02 pm
by eradicator
I used ctrl+f "players"...and found "players :: array of LuaPlayer [Read-only]". That was players.force though, duh. Which suprisingly seems to be accurate. (Suprising in that force.players is *not* a custom table). All the more reason to go back to pairs everywhere :/.

Re: pairs() vs next() with userdata objects?

Posted: Fri May 10, 2019 7:17 pm
by quyxkh
Using `next` is a declaration that the table's a plain lua table. `pairs` looks up iterator arguments for what you pass it, if it's a plain lua table it returns `next` and the table, otherwise it uses whatever the metatable says. For lua tables that have a metatable with an overriding `__pairs`, using `next` will bypass that, which might or might not be what you want; for custom tables (i.e. userdata tables), where pretty much the entire point is not to use a lua table for the meat, `next` isn't likely to do anything useful.

Re: pairs() vs next() with userdata objects?

Posted: Fri May 10, 2019 7:23 pm
by eradicator
quyxkh wrote:
Fri May 10, 2019 7:17 pm
for custom tables (i.e. userdata tables), where pretty much the entire point is not to use a lua table for the meat, `next` isn't likely to do anything useful.
Just for clarification, the issue originally was in my collection of generic table functions where i don't know what kind of table is coming in. I do appreciate all the detailed explanations though.