[2.0.64] LuaGuiElement.add woes with sparse arrays?
[2.0.64] LuaGuiElement.add woes with sparse arrays?
consider this code:
local handler = {
[defines.events.on_gui_checked_state_changed] = 'onSort',
}
local child = element.add {
type = 'checkbox',
...
tags = {
value = sort_value,
entity_type = entity_type,
handler = handler,
},
}
Looking at this in the debugger shows this:
so the numeric index 3 (which is on_gui_checked_state_changed) in the handler array has been converted to a string.
However, using on_click, which is 1 shows this:
This seems to be a problem with an array that does not start at 1. It gets converted to a table (and all keys are now strings). If the array starts at 1, it is treated as an array.
This came as a surprise as lua clearly supports sparse arrays. But it seems the conversion from/to the C++ code when calling LuaGuiElement.add) gets confused.
local handler = {
[defines.events.on_gui_checked_state_changed] = 'onSort',
}
local child = element.add {
type = 'checkbox',
...
tags = {
value = sort_value,
entity_type = entity_type,
handler = handler,
},
}
Looking at this in the debugger shows this:
so the numeric index 3 (which is on_gui_checked_state_changed) in the handler array has been converted to a string.
However, using on_click, which is 1 shows this:
This seems to be a problem with an array that does not start at 1. It gets converted to a table (and all keys are now strings). If the array starts at 1, it is treated as an array.
This came as a surprise as lua clearly supports sparse arrays. But it seems the conversion from/to the C++ code when calling LuaGuiElement.add) gets confused.
Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?
In lua, there is no special type for array table or for dictionary table, this is all user space interpretation of a generic lua table based on the table keys and lack of gaps within numeric indexes. I will just throw this to Not a bug.
Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?
While I agree with the "it is all user space interpretation", the surprising part (and the bug IMHO) is that one should be able to expect to read back from the table what you wrote. So when I create a new LuaGuiElement with tags:
Now I would expect to be able to read back child.tags.xxx[defines.events.on_gui_checked_state_changed] and get the 'onSort' value. And that works if this is defines.events.on_click because that happens to be 1.
So now, my code has turned into
which seems less than ideal.
Code: Select all
child = parent.add {
...
tags = {
xxx = {
[defines.events.on_gui_checked_state_changed] = 'onSort'
}
},
...
}
So now, my code has turned into
Code: Select all
event = defines.events.on_gui_checked_state_changed
foo = child.tags.xxx[event] or child.tags.xxx[tostring(event)]
which seems less than ideal.
Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?
Ok, lets slow down and reiterate. When i run following command:
i get following output:
Why is it working even when it was not supposed to work based on your report?
If you get a table dump in a form of { "bar" }, that means function that does the dumping realized that this table consists of single record of key=1 value="bar", and to save space, instead of dumping it as { [1] = "bar" }, a shorter format was used. This value is still available at index 1. Can you show me a piece of code that does not work when a table is put into tags then retrieved?
Code: Select all
/c
local foo = { [3] = "onSort inside foo" }
game.print(serpent.line(foo))
game.print(foo[3])
local bar = { [1] = "onSort inside bar" }
game.print(serpent.line(bar))
game.print(bar[1])
local qux = { "onSort inside qux" }
game.print(serpent.line(qux))
game.print(qux[1])
Code: Select all
{[3] = "onSort inside foo"}
onSort inside foo
{"onSort inside bar"}
onSort inside bar
{"onSort inside qux"}
onSort inside qux
If you get a table dump in a form of { "bar" }, that means function that does the dumping realized that this table consists of single record of key=1 value="bar", and to save space, instead of dumping it as { [1] = "bar" }, a shorter format was used. This value is still available at index 1. Can you show me a piece of code that does not work when a table is put into tags then retrieved?
Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?
Yes, this is all correct. The problem is that "passing a table with values as a tag into the "LuaGuiElement.add" method makes it return a LuaGuiElement instance which contains the tags, but *there* the keys have been replaced with strings *unless* it is the index 1.boskid wrote: Tue Aug 19, 2025 7:23 pm Ok, lets slow down and reiterate. When i run following command:
i get following output:Code: Select all
/c local foo = { [3] = "onSort inside foo" } game.print(serpent.line(foo)) game.print(foo[3]) local bar = { [1] = "onSort inside bar" } game.print(serpent.line(bar)) game.print(bar[1]) local qux = { "onSort inside qux" } game.print(serpent.line(qux)) game.print(qux[1])
Why is it working even when it was not supposed to work based on your report?Code: Select all
{[3] = "onSort inside foo"} onSort inside foo {"onSort inside bar"} onSort inside bar {"onSort inside qux"} onSort inside qux
If you get a table dump in a form of { "bar" }, that means function that does the dumping realized that this table consists of single record of key=1 value="bar", and to save space, instead of dumping it as { [1] = "bar" }, a shorter format was used. This value is still available at index 1. Can you show me a piece of code that does not work when a table is put into tags then retrieved?
This is not a general lua table interpretation problem. My assumption is that the GUI code is written in C++ and the data I pass into C++ is marshalled into some internal representation and when I read it back from the child element created by LuaGuiElement.add, the table gets converted back from the C++ interpretation. Somewhere in that process, the keys are converted from numbers to strings.
Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?
You can not reproduce this by using the lua command line or the debugger console; it is specific to LuaGuiElement.add and tags.
Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?
Ok finally i see, you are reporting that a numeric key becomes a string key while saved into tags and then read back. Essentially a reproduction is that running this command:
produces this output:
and it is expected that both lines are equal.
I was looking at the value of "handler" in your watch list while i was supposed to look at the value of child.tags.handler.
Code: Select all
/c
local foo = { [3] = "bar" }
game.print(serpent.line(foo), {skip=defines.print_skip.never})
storage.checkbox = game.player.gui.top.add{
type = 'checkbox',
state = true,
tags =
{
handler = foo
}
}
foo = storage.checkbox.tags.handler
game.print(serpent.line(foo), {skip=defines.print_skip.never})
Code: Select all
{[3] = "bar"}
{["3"] = "bar"}
I was looking at the value of "handler" in your watch list while i was supposed to look at the value of child.tags.handler.
Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?
Yes. Sorry for not being clearer in the original post, it was late at night. 
The “numeric key becomes a string key” is the problem/bug.

The “numeric key becomes a string key” is the problem/bug.
Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?
See also 104565
I'm an admin over at https://wiki.factorio.com. Feel free to contact me if there's anything wrong (or right) with it.