Page MenuHomePhabricator

Order of tables passed to PHP is not preserved when using LuaStandalone
Closed, DuplicatePublicBUG REPORT

Description

Steps to replicate the issue (include links if applicable):

local p = {}

function p.example()
  local json = '["a", "b", "c", "d", "e", "f", "g", "h"]';
  local arr = mw.text.jsonDecode(json);

  return mw.af.export(arr);
end

return p
  • Observe the result of invoking this module:

Screenshot 2023-10-24 at 11.04.03.png (1×1 px, 104 KB)

What happens?:
The order of the table is random.

What should have happened instead?:
The order of the table is preserved.

Software version (skip for WMF-hosted wikis like Wikipedia):
MediaWiki: 1.39.4
Lua: 5.1.5 (standalone)

Other information (browser name/version, screenshots, etc.):
This seems to happen because pairs (as opposed to ipairs) is used in the MWServer:serialize function. Looping over the table using pairs in Lua directly shows this:

local p = {}

function p.example()
  local json = '["a", "b", "c", "d", "e", "f", "g", "h"]';
  local arr = mw.text.jsonDecode(json);

  for k, v in pairs(arr) do
    mw.log(k, v);
  end
end

return p
6	f
2	b
8	h
3	c
1	a
4	d
5	e
7	g

Using ipairs gives the correct (ordered) result. Interestingly, building a new table from the old one fixes the problem:

local p = {}

function p.test()
  local json = '["a", "b", "c", "d", "e", "f", "g", "h"]';

  local arr = mw.text.jsonDecode(json);
  local new_arr = {};

  for k, v in pairs(arr) do
    new_arr[k] = v;
  end

  for k, v in pairs(new_arr) do
    mw.log(k, v)
  end
end

return p
1	a
2	b
3	c
4	d
5	e
6	f
7	g
8	h

Event Timeline

Izno subscribed.

If instead you think this can be resolved in the source of ArrayFunctions, you may reopen and change the project to MediaWiki-extensions-ArrayFunctions .

@Izno, that task is about communication from PHP to Lua, while this task is about communication from Lua to PHP. Is this really a duplicate?

Thinking about it, the root cause might also be the communication from PHP to Lua happening after calling mw.text.jsonDecode, in which case closing this as a duplicate makes sense.