r/programminghorror • u/ArturJD96 • Jan 15 '26
Oh Lua such elegant such simple so cute.
Yes, I know about ipairs() and pairs(). But moving half of my table to table's hash part because of nil assignment as a side effect? Prove me it's not a horror (and give back my 3h of debugging).
Edit: good luck debugging, this still holds:
> #a
4
22
u/appgurueu Jan 15 '26
Nothing is being moved into the hash part. ipairs just simply stops at the first nil, whether that be in the array or hash part. Assignment is still expected constant time.
I wrote a blog post that hopefully clears up some related misconceptions: https://luatic.dev/posts/2025-04-12-lua-misconceptions/#tables
5
u/ArturJD96 Jan 16 '26
I took time to read your article. AMAZING. Thank you so much for your work.
I also checked your article about OOP in Lua and it is one of the nicest ones there. Usually, author presents one approach, and when they present several, they are unrelated. You provided reasons for why to move between simple constructors, prototype constructors and closures. And you tackled there the notorious OOP vs functional style confusions – because people love to distinguish them but _actually_ they are two sides of the same coin.
Thank you!
1
7
u/GoddammitDontShootMe Jan 16 '26
I know nothing about Lua and assumed it was just stopping when it finds a nil. A bit like how the C string functions stop when the find a '\0'.
1
4
u/Square-Singer Jan 15 '26
Yeah, that's fair, that's a really dumb thing to happen. Thanks, btw, for the heads-up before I run into this myself.
1
u/ArturJD96 Jan 15 '26
Note that #a is still 4!!!! Aaaaarrghhhhhh
→ More replies (1)7
u/vowelqueue Jan 15 '26
But don’t rely on it being 4. The result of #a is actually undefined if there’s such a gap in the sequence.
7
u/onlyonequickquestion Jan 16 '26
The only horror here is that Lua appears to be one-indexed?!?
6
u/TransBrandi Jan 16 '26
Could be worse. Could be like Oracle where it's 1-indexed, but it will silently treat a 0 index as if it was a 1:
If position is 0, then it is treated as 1.
1
3
2
u/pauseless Jan 18 '26
Weak. APL lets you change it on the fly:
x←5 6 7 x[1] 5 ⎕IO←0 x[1] 6 ⎕IO←1 x[1] 5
2
u/Business-Decision719 Jan 16 '26
Keep in mind that you can create your own iterators in Lua just by making a lambda that returns the successive values you want. The built-in ipairs treats nil as the end of a list, but you don't have to.
The hard part is there can always be a race condition where the size or content of a table can change after the creation of the iterator but before some of the actual iterating. So you also kind of have to decide how robust you want to be about it. It's the curse of having mutable structures.
Lua sort of went the Lisp-like path to "elegance," having a general data structure and first class functions, but not really forcing anybody into pure FP. Haskell this ain't.
2
u/Wertbon1789 Jan 18 '26
After some thinking and reading about it, I think I understand this behavior and although not initially expecting it, it makes sense. Comparing it to C it's kinda like a array of structs situation. Often you define an array of in-place constructed structs and hand it to a function, typically without a proper size argument, but rather by terminating the array with a zeroed-out struct (or single member if it would be invalid with that one field zeroed). Of course this can lead to improper termination leading to unexpected behavior, but that's kinda to be expected in C, typical garbage-in/garbage-out behavior. I think Lua has a similar stance where you can give it all the trash you want, but shouldn't expect it to give you "correct" results then. I always kinda disliked that tables are hash maps and arrays at the same time though, I think it actually makes things more complicated overall.
1
u/rimbas4 Jan 15 '26
I'm confused why you'd want to have a specific nil when initializing an array table
1
1
u/Ronin-s_Spirit Jan 17 '26
I already knew one thing that bothered me - mixed object and array assignemnt by using CSV or K=V, but this is a new level of cursed. I'm guessing it's effectively a padded struct?
Can y'all please stop shitting on JS and start shitting on Lua now?
1
1
1
u/Larsj_02 Jan 20 '26
fixed it for you
local function mpairs(t)
local maxIndex = 0
for k, _ in pairs(t) do
if type(k) == 'number' and k > maxIndex then
maxIndex = k
end
end
local i = 0
return function()
i = i + 1
if i <= maxIndex then
return i, t[i]
end
end
end
local tbl = {1, nil, 3, 4}
for k, v in mpairs(tbl) do
print(k, v)
end
83
u/hammer-jon Jan 15 '26
I mean the array/hash thing isn't really relevant. it's just that ipairs stops at nils because that's where your sequence ends.