[2.0.64] LuaGuiElement.add woes with sparse arrays?

Post your bugs and problems so we can fix them.
User avatar
hgschmie
Fast Inserter
Fast Inserter
Posts: 132
Joined: Tue Feb 06, 2024 5:18 am
Contact:

[2.0.64] LuaGuiElement.add woes with sparse arrays?

Post by hgschmie »

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:
Screenshot 2025-08-18 at 23.06.16.png
Screenshot 2025-08-18 at 23.06.16.png (18.27 KiB) Viewed 418 times
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:
Screenshot 2025-08-18 at 23.08.37.png
Screenshot 2025-08-18 at 23.08.37.png (20.32 KiB) Viewed 418 times
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.
User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 4118
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?

Post by boskid »

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.
User avatar
hgschmie
Fast Inserter
Fast Inserter
Posts: 132
Joined: Tue Feb 06, 2024 5:18 am
Contact:

Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?

Post by hgschmie »

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:

Code: Select all


child =  parent.add {
    ...
    tags = {
        xxx = {
            [defines.events.on_gui_checked_state_changed] = 'onSort' 
        }
    },
    ...
}
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

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.
User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 4118
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?

Post by boskid »

Ok, lets slow down and reiterate. When i run following command:

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])
i get following output:

Code: Select all

{[3] = "onSort inside foo"}
onSort inside foo
{"onSort inside bar"}
onSort inside bar
{"onSort inside qux"}
onSort inside qux
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?
User avatar
hgschmie
Fast Inserter
Fast Inserter
Posts: 132
Joined: Tue Feb 06, 2024 5:18 am
Contact:

Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?

Post by hgschmie »

boskid wrote: Tue Aug 19, 2025 7:23 pm Ok, lets slow down and reiterate. When i run following command:

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])
i get following output:

Code: Select all

{[3] = "onSort inside foo"}
onSort inside foo
{"onSort inside bar"}
onSort inside bar
{"onSort inside qux"}
onSort inside qux
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?
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.

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.
User avatar
hgschmie
Fast Inserter
Fast Inserter
Posts: 132
Joined: Tue Feb 06, 2024 5:18 am
Contact:

Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?

Post by hgschmie »

You can not reproduce this by using the lua command line or the debugger console; it is specific to LuaGuiElement.add and tags.
User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 4118
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?

Post by boskid »

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:

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})
produces this output:

Code: Select all

{[3] = "bar"}
{["3"] = "bar"}
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.
User avatar
hgschmie
Fast Inserter
Fast Inserter
Posts: 132
Joined: Tue Feb 06, 2024 5:18 am
Contact:

Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?

Post by hgschmie »

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.
Bilka
Factorio Staff
Factorio Staff
Posts: 3543
Joined: Sat Aug 13, 2016 9:20 am
Contact:

Re: [2.0.64] LuaGuiElement.add woes with sparse arrays?

Post by Bilka »

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.
Post Reply

Return to “Bug Reports”