Lists; a fast way to store objects.

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: Lists; a fast way to store objects.

Post by airstruck »

zorg wrote: Not that this would be that common of a scenario either, but:

Code: Select all

local yesThisIsLuaCode = nil -- (ignore this)
t[#t] = t[i] -- move old to end
t[i]  = e -- new element inserted wherever wanted
-- or in a more concise form:
t[#t], t[i] = t[i], e
is completely possible, if you both want to insert stuff at a specific location, and don't care that whatever was there is now not. Granted, the first one doesn't make that much sense (caring about insertion position) when we don't care about the second one (order) either, but who knows; maybe someone would find a use-case i didn't think of. :)
Didn't catch this earlier, but I think this part is backwards:

Code: Select all

local yesThisIsLuaCode = nil -- (ignore this)
t[#t], t[i] = t[i], e
Multiple assignments are done from right to left, something the manual never seems to mention (I don't think this is widely known; I've never actually seen it mentioned anywhere). You can verify it like this:

Code: Select all

t = setmetatable({}, { __newindex = function (t, i, v) print(i, v) end })
t[1], t[2] = 10, 20
So instead you'd need to do this, otherwise you'll get two copies of e (unless i == #t):

Code: Select all

local yesThisIsLuaCode = nil -- (ignore this)
t[i], t[#t] = e, t[i]
Likewise, removing an element by moving the last element to its position and then nilling the last element needs to be written like this when using multiple assignment:

Code: Select all

local yesThisIsLuaCode = nil -- (this is obnoxious)
t[#t], t[i] = nil, t[#t]
...which looks a little counterintuitive, but if you do it the other way around, it will fail when i == #t (because all expressions are evaluated before any assignment is done, as the manual mentions, and because the assignments are done from right to left, as it doesn't mention).
User avatar
zorg
Party member
Posts: 3441
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Lists; a fast way to store objects.

Post by zorg »

I was under the impression that in a multiple assignment line, the RHS-es get evaluated first, then get assigned to the LHS-es... i might be wrong though, but that would imply that the following would happen:

Code: Select all

local theForumSupportsIIRCJavascriptAsWellForSomeReasonSoTheSyntaxHighlightCanMessUpOnShortEnoughCodeSnippets = nil -- :v
a=5;b=7
a,b = b,a --> a,b = 7,5 -> a=7,b=5
-- So, it should follow that: (e.g. t[i]==5 and e==7)
t[#t+1], t[i] = t[i], e --> t[#t+1], t[i] = 5, 7 --> t[#t+1]=5,t[i]=7
Edit: I think i actually made a mistake, so i edited the above code to reflect what i originally meant. (Insertion at specific place, move whatever was at insertion index to AFTER the end, not overwrite the last element...)

In any case, this code works flawlessly on the online lua testbed:

Code: Select all

local t = {1,2,3,4,5,6}
local i = 2
local e = 7
t[#t+1], t[i] = t[i], e
for i=1,#t do print(i,t[i]) end
--[[result:
1	1
2	7
3	3
4	4
5	5
6	6
7	2
--]]
and i didn't get two copies of e with it.
Last edited by zorg on Fri Dec 30, 2016 8:13 pm, edited 3 times in total.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: Lists; a fast way to store objects.

Post by airstruck »

All of the lhs and rhs (of the equals sign) get evaluated first (for example a #t on the left is evaluated before any assignments), but then assignments are made from right to left:

Code: Select all

a, b, c = 1, 2, 3
-- is equivalent to
c = 3
b = 2
a = 1
User avatar
zorg
Party member
Posts: 3441
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Lists; a fast way to store objects.

Post by zorg »

I edited my post above to include a test, and fixed what i originally meant to do, though whether it's #t or #t+1 should not matter much regarding the points you're making; since everything gets evaluated, assignment order in that case becomes moot, i think.
In a case of

Code: Select all

t[1], t[1] = 2, 3
(to rid ourselves of the variable indirection for it to be more clear and to-the-point), it does matter whether t[1] becomes 3 or 2, but you'd usually not assign to the same thing one after another, let alone in one line.

But you are right, in the last case, t[1] does become 2, so it does go from right to left.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
pgimeno
Party member
Posts: 3548
Joined: Sun Oct 18, 2015 2:58 pm

Re: Lists; a fast way to store objects.

Post by pgimeno »

This sounds like a slippery slope. Depending on assignment order falls into the "don't do it" category. Kind of like the famous i=i++ in C. I wouldn't be surprised if that changed between Lua and LuaJIT, or between versions of Lua or of LuaJIT.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: Lists; a fast way to store objects.

Post by airstruck »

pgimeno wrote:This sounds like a slippery slope. Depending on assignment order falls into the "don't do it" category. Kind of like the famous i=i++ in C. I wouldn't be surprised if that changed between Lua and LuaJIT, or between versions of Lua or of LuaJIT.
Yeah, it's definitely UB as far as I can tell. Probably best not to rely on multiple assignment when assignment order matters. Although practically, more things than this will break between Love versions, so maybe not a big deal except for in code that's supposed to be future-proof, like library code with no Love-specific stuff in it.
User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Lists; a fast way to store objects.

Post by raidho36 »

It's not just that - any difference between Lua implementations can result in different outcomes. You may get different results on PC and mobile because they use different version of LuaJIT, and versions of LÖVE that are built with standard Lua may also yield different results. And even within the same version, minute differences in host platform can impact outcomes as well.

The machine is free to do however it pleases each and every time it has to evaluate a structure with no defined behavior. This is precisely why you not merely don't rely on UB, but you always actively avoid it, period.
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: Lists; a fast way to store objects.

Post by airstruck »

raidho36 wrote:This is precisely why you not merely don't rely on UB, but you always actively avoid it, period.
Not sure what the difference is, but yeah, best to avoid it. I should have mentioned that it's always been like this for as long as I can remember, in every version of Lua I've ever seen, and I've never actually checked the manual until now, so it really never occurred to me that it's actually UB (until now, I always thought of it as an obscure implementation detail but never bothered to check whether behavior was actually defined).
User avatar
zorg
Party member
Posts: 3441
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Lists; a fast way to store objects.

Post by zorg »

Glad all of you agree on something, but that still doesn't change the fact that my original example airstruck took apart didn't have the issue you guys were discussing. :P
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: Lists; a fast way to store objects.

Post by Inny »

airstruck wrote:All of the lhs and rhs (of the equals sign) get evaluated first (for example a #t on the left is evaluated before any assignments), but then assignments are made from right to left:

Code: Select all

a, b, c = 1, 2, 3
-- is equivalent to
c = 3
b = 2
a = 1
Just to clarify this, Lua evaluates left to right, and then assigns right to left (as the results have landed in the stack). We can see this when we use luac on this code:

Code: Select all

function a() return 1 end
function b() return 2 end
function c() return 3 end

x, y, z = a(), b(), c()
Thankfully luac has kind enough to comment the variables:

Code: Select all

main <test_eval_order.lua:0,0> (16 instructions, 64 bytes at 009482F8)
0+ params, 3 slots, 0 upvalues, 0 locals, 6 constants, 3 functions
        1       [1]     CLOSURE         0 0     ; 00948408
        2       [1]     SETGLOBAL       0 -1    ; a
        3       [2]     CLOSURE         0 1     ; 00948368
        4       [2]     SETGLOBAL       0 -2    ; b
        5       [3]     CLOSURE         0 2     ; 00948AF0
        6       [3]     SETGLOBAL       0 -3    ; c
        7       [5]     GETGLOBAL       0 -1    ; a
        8       [5]     CALL            0 1 2
        9       [5]     GETGLOBAL       1 -2    ; b
        10      [5]     CALL            1 1 2
        11      [5]     GETGLOBAL       2 -3    ; c
        12      [5]     CALL            2 1 2
        13      [5]     SETGLOBAL       2 -6    ; z
        14      [5]     SETGLOBAL       1 -5    ; y
        15      [5]     SETGLOBAL       0 -4    ; x
        16      [5]     RETURN          0 1

function <test_eval_order.lua:1,1> (3 instructions, 12 bytes at 00948408)
0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions
        1       [1]     LOADK           0 -1    ; 1
        2       [1]     RETURN          0 2
        3       [1]     RETURN          0 1

function <test_eval_order.lua:2,2> (3 instructions, 12 bytes at 00948368)
0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions
        1       [2]     LOADK           0 -1    ; 2
        2       [2]     RETURN          0 2
        3       [2]     RETURN          0 1

function <test_eval_order.lua:3,3> (3 instructions, 12 bytes at 00948AF0)
0 params, 2 slots, 0 upvalues, 0 locals, 1 constant, 0 functions
        1       [3]     LOADK           0 -1    ; 3
        2       [3]     RETURN          0 2
        3       [3]     RETURN          0 1
The first 6 lines of CLOSURE SETGLOBAL pairs are creating a, b, and c functions. Then the evaluation takes the next 6 lines in GETGLOBAL CALL pairs, and the assignment is the next three SETGLOBAL lines.

Yay stack-based VM!
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Majestic-12 [Bot] and 157 guests