Compact Representations for Arrays in Lua [pdf]

sol.sbc.org.br

67 points

tkhattra

14 days ago


21 comments

nzzn 10 days ago

Lua uses the table type to represent both dictionaries (hash tables) and arrays of values. This seems to have been predicated on keeping the language “simple” with a minimal number of defined types. A laudable goal.

However, arrays of a single type are just enormously common in applications. Support for arrays is pretty much ubiquitous in other languages, including ones that are in the same general dynamic space.

Internally Lua does treat arrays in their own pathway to keep performance reasonable. There is also some user facing special syntax for arrays. Arrays should be part of the core language — some learning overhead for the newcomer but worth it.

  • ufo 10 days ago

    I think the real issue here is not whether there is a separate type for tables and arrays, but whether the arrays are homogenous (all elements must have the same type). In most dynamic languages, the arrays are heterogeneous. For example, Python has a separate array type, but if you want homogenous arrays you have to reach for something like numpy.

marhee 11 days ago

I wonder, in reality, if a Lua program uses large (consecutive) arrays, its values will likely have the same type? At the very least it is a common use-case: large arrays of only strings, numbers etc. Wouldn’t it make sense to (also) optimize just for this case with a flag and a single type tag. Simple and it optimizes memory use for 98% of use cases?

  • ufo 10 days ago

    The main catch is that if the optimization guesses wrong and a different type is inserted into the table afterwards, then it would incurr an O(n) operation to transfer all the data to a deoptimized table.

    Another caveat is that Lua can have more than one internal representation for the same type, and those have different type tag variants. For instance: strings can be represented internally as either short or long strings; Functions can be Lua closures, C closures, or perhaps even an object with a __call metamethod; Objects can be either tables or userdata.

  • tedunangst 11 days ago

    This seems likely to create some inexplicable performance elbows where you have 1000 strings, but there's one code path that replaces one with a number, and now the whole array needs to be copied. Tracking that down won't be fun.

  • Jyaif 11 days ago

    It makes a lot of sense, and but then you have two code paths for tables.

    The Lua folks want a simple codebase, so they (knowingly) leave a lot of performance on the table in favor of simplicity.

    • ufo 10 days ago

      For what it's worth, there are already two code paths for tables. The array part is stored separately from the hash table part.

kzrdude 11 days ago

It was published in September 2024, so it's relatively recent.

Jyaif 11 days ago

Jesus christ, 40% waste in arrays that can be solved by using `__attribute__((packed))`.

Irresponsible of them of not advertising this as an option in luaconf.h

  • sfpotter 11 days ago

    Here's the rest of that paragraph for you:

    "However, this attribute is a gcc extension not present in ISO C. Moreover, even in gcc it is not guaranteed to work [3]. As portability is a hallmark of Lua, this almost magical solution is a no-go."

    • Jyaif 11 days ago

      [flagged]

      • mananaysiempre 11 days ago

        Embedders of Lua are not equidistributed across platforms with the general population of programmers or with user-exposed general-purpose computers. Not even close. One of the selling points of Lua is how easy it is to run on a toaster or potato, so disproportionately many ports of Lua are in fact running on toasters and potatoes.

      • kragen 11 days ago
        4 more

        You have no idea what 90% of their users are using. A lot of them aren't using LLVM or GCC. I'm pretty sure Roblox and WoW, for example, aren't normally compiled with LLVM or GCC. Whether those two games account for 99% of Lua's users or 0.001% depends on how you count, but no matter how you count, you have no idea.

        • debugnik 11 days ago
          2 more

          Roblox accounts for 0% of stock Lua users, they run Luau. And many uses of Lua you come up with will be using LuaJIT or pinned to an older, possibly forked, Lua release.

          I'm not agreeing with the comment you replied to, just nitpicking.

          • kragen 11 days ago

            You have good points.

        • canyp 11 days ago

          [flagged]

      • nxobject 11 days ago

        The USP of Lua is the fact that's its easy to target embedded and microcontroller with funky/frozen toolchains -- that's why PUC-Rio Lua is written in C89. You're just as likely to have to use a "#pagma packed" as an attribute.

  • ethan_smith 11 days ago

    `__attribute__((packed))` wouldn't help here since the issue is about Lua's array/hash hybrid table design and memory allocation strategy, not C struct padding.

    • lifthrasiir 11 days ago

      But it did help in the other way, in my reading of the paper [1]. So the OP is asking why this is not even an option on supported environments, and I too think that this is indeed a good question to ask.

      [1] "Hugo Gualandi reported that just adding the gcc attribute __attribute__((packed)) to the definition of the structure TValue reduces its size from 16 to 9 bytes, without any sensible difference in performance."

      • hugomg 10 days ago

        We figured that it wasn't worth dealing with the hassle of unaligned addresses because the more portable alternatives worked just as well.