A Developer's Awkward Introduction to Lua's Infamous Quirks
Description
A four-panel comic strip humorously depicting the experience of learning the Lua scripting language. In the first panel, a character with a blue outline enthusiastically points to a building with a 'Lua' sign and logo, telling a plain white character, 'THIS IS MY FAVORITE Scripting Language'. Through a small door in the building, a smaller, red-outlined character is seen drinking from a bottle. The second panel is a silent close-up of the plain character looking skeptical and the blue character starting to sweat. In the final panel, the red character, now outside and holding the bottle, belligerently explains Lua's core concepts in a jagged speech bubble: 'Objects? Everything is a Table, Arrays start at 1,'. The blue character looks on with a strained, sweaty expression of regret. The technical humor stems from Lua's unconventional design choices that defy programming norms, specifically its 1-based array indexing (most languages are 0-based) and its reliance on a single 'table' data structure for everything, which can be jarring for developers accustomed to distinct objects, arrays, and dictionaries
Comments
37Comment deleted
Lua is the reason senior game devs have trust issues. After years of fighting off-by-one errors, you're suddenly told the real mistake was starting at zero all along
Lua: the only place where shifting every array by +1 is considered both an object model and a design philosophy
After 20 years of explaining why our Redis Lua scripts have off-by-one errors in production, I've concluded that Lua's 1-based indexing isn't a design choice - it's a distributed systems resilience test disguised as a scripting language feature
Lua developers will passionately defend 1-based indexing as 'more intuitive for non-programmers' while simultaneously explaining why implementing OOP requires understanding metatables, the __index metamethod, and why `setmetatable({}, {__index = ParentClass})` is 'simple.' It's the language equivalent of saying 'we simplified everything' and then handing you a table that's simultaneously an array, object, hashmap, namespace, and occasionally your entire module system
Lua: Where tables impersonate objects flawlessly, but that 1-based array has you subtracting instinctively at every embed
Lua: where OO is sugar on hash maps and off-by-one is a spec, not a bug
Embedding Lua is great - until your C++ indices meet its 1-based tables and your ‘object system’ is a metatable and a prayer
well, yes, that's why Comment deleted
"everything is a table" i can accept, but "arrays start at 1"? What fresh hell is this? TurboPascal? Comment deleted
Maybe index 0 is used for storing array length. That way walking the array to find the length is not needed. Just a guess. Comment deleted
That's exactly what TurboPascal had, especially in terms of strings :) first byte was string length :) Comment deleted
This wouldn't have any use. Many managed languages store raw structs or arrays this way but they will account for it Comment deleted
Arrays starting at 0 comes from languages like C where position in the array is the memory offset. Offset 0 makes the most sense for those languages. Now most languages don't store arrays/lists in contiguous addresses, so there's no offset used there. For those languages, starting with 1 makes the most sense. Think about it - if you need the first element, you need to type 0. If you need nth element, you always have to count n-1 in your head. The length is always position of the last element +1. If you have array of 6 elements, with 0-based indexing you have to position of the last element = length -1 So, I'd actually prefer 1-based indexing, it is just less complexity that is now mostly not needed Comment deleted
We are doomed then. Do those languages reinvent virtual memory management on software level?! 🥴 As for "offset" thing, the reasoning is simple: lower-level languages that sit near hardware as much as possible, use offsets, while higher-level languages for educational and casual user audience tend to use natural numbers as indices. There is also a corner case with math, where storing polynomial coefficients will naturally benefit from starting at zero, but as well as from ability to have negative indices (some languages support that). Comment deleted
Well, what I meant that it is not guaranteed that the values will be stored in contiguous blocks of memory - I'm talking about higher-level languages where an array is dynamic and its size can be changed at runtime. For lower-level languages 0-based indexes make sense, of course. Comment deleted
Dutch count floors in a building differently too. Comment deleted
so you selected the whole message instead of replying 😌 Comment deleted
You probably mean associative arrays (dictionaries) and all other kinds of that. Regular arrays may also be dynamic, if the language supports it in one form or another, such as: Dim a(1 To 23) As Integer ReDim Preserve a(1 To 42) or int *a = malloc(23 * sizeof(int)); a = realloc(a, 42 * sizeof(int)); or std::list<int> a(23); a.resize(42); but all those are simple contiguous blocks of memory, reallocated on resize. Comment deleted
I see. I think it depends on the language, I've heard python's lists are basically linked lists behind the scenes, so I assume the values can be stored all over the place in memory Also, for me arrays==lists (in concept, not in implementation) - an ordered collection of values :) I live a simple life😅 Comment deleted
Sorry, but arrays starting at 1 makes no sense whatsoever. Most of the time you do not need indices at all but just want to loop over the elements. When you actually need indices, you'll just end up having to subtract 1 first, then do the math and finally add back 1 again. *Mic drop* Comment deleted
If you want to access the last value, you have to do my_list[my_list.length -1] all the time though (if it is not python, where you can just my_list[-1] If you use 0-based indexes then you have to do +/- 1 Comment deleted
How many elements exist between 0 and 5? How many elements exist between -3 and 2, and at which indices? Comment deleted
We didn't have for each loops back then — only for and while. (PS. Lisp doest not counr.) When you actually need indices, you'll just end up having to subtract 1 first, then do the math and finally add back 1 again. *Mic drop* This is exactly what Visual Basic .NET is doing: it does not allow having arrays starting from anything but zero, but still uses classic syntax of dimensioning with lower and upper bounding indices: Dim a(0 to n - 1) only to be translated to the intermediate code that subracts and imnediately adds 1 to get the number of elements for allocation: pop sub 1 add 1 dim "Complier will optimize!"?! Ha-ha! Comment deleted
Looks like lua is programmable excel sheet, they both start at 1 Comment deleted
Are lua Tables more like python dictionaries or c structs? Comment deleted
Actually nowadays they are a bit of both I think it uses an array part only when there are contiguous indices 1..x And a map otherwise? Comment deleted
_G Comment deleted
Fun fact: lua(jit) is used for a business logic impl of highload-oriented services, like haproxy runtime, Tarantool DB runtime.. (surely its gc becomes a mess at some point, but.. I love the) Comment deleted
well, that's just a map Comment deleted
yeah, exactly, because lua arrays are also tables Comment deleted
I love lua, apart from having arrays start with 1 it's a great language Comment deleted
Most wikis run it😂🙈 Comment deleted
AFAIK in Lua arrays can start at any index you want. Not just 0 or 1 Comment deleted
Which language are you talking about? Lua tables definitely do not have a .length member. It's #my_list. Comment deleted
.length is in js, but it doesn't matter what language it is, the concept is the same Comment deleted
writing lua scripts for redis felt like writing xslt v1.0 Comment deleted
OpenResty is fun too Comment deleted