Using unpack() twice in a single function call

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Using unpack() twice in a single function call

Framework Studios: Hugo
Hi,
 
In the following code...
 
function Caller()
    local a = {23, 45}
    local b = {-1, -2}
    F(unpack(a), unpack(b))
end
 
...I would expect F to be called with 4 parameters.
 
However:
 
function F(p1, p2, p3, p4)
    log(p1)
    log(p2)
    log(p3)
    log(p4)
end
 
Caller()
 
...then logs:
 
23
-1
-2
(null)
 
Is there any way to use more than one unpack() in a single function call? I'm using Lua 5.1 with LuaJIT btw.
 
    Thanks,
 
            Hugo
 
Reply | Threaded
Open this post in threaded view
|

Re: Using unpack() twice in a single function call

Andreas Stenius-2
Framework Studios: Hugo skrev:
[...]

Is there any way to use more than one unpack() in a single function call? I'm using Lua 5.1 with LuaJIT btw.

Nope, see: http://www.lua.org/manual/5.1/manual.html#2.5

Specifically this part:
"Both function calls and vararg expressions may result in multiple values. If the expression is used as a statement (see §2.4.6) (only possible for function calls), then its return list is adjusted to zero elements, thus discarding all returned values. If the expression is used inside another expression or in the middle of a list of expressions, then its result list is adjusted to one element, thus discarding all values except the first one. If the expression is used as the last element of a list of expressions, then no adjustment is made, unless the call is enclosed in parentheses."

The examples after this text are pretty descriptive as well.

//Andreas

Reply | Threaded
Open this post in threaded view
|

Re: Using unpack() twice in a single function call

Aaron Brown
In reply to this post by Framework Studios: Hugo
Hugo wrote:

    F(unpack(a), unpack(b))

Is there any way to use more than one unpack() in a single
function call?

As Andreas pointed out, everything but the last expression
gets adjusted to one value.

You might find something like this useful:

-- Like unpack, but accepts multiple arguments:
function multunpack(...)
 local ret = {}
 for i = 1, select("#", ...) do
   for _, rec in ipairs(select(i, ...)) do
     ret[#ret + 1] = rec
   end -- _, rec
 end -- i
 return unpack(ret)
end -- multunpack

print(multunpack({23, 45}, {-1, -2}))
23      45      -1      -2

--
Aaron


Reply | Threaded
Open this post in threaded view
|

Re: Using unpack() twice in a single function call

Javier Guerra Giraldez
On Friday 04 August 2006 12:42 pm, Aaron Brown wrote:
> -- Like unpack, but accepts multiple arguments:
> function multunpack(...)
>   local ret = {}
>   for i = 1, select("#", ...) do
>     for _, rec in ipairs(select(i, ...)) do
>       ret[#ret + 1] = rec
>     end -- _, rec
>   end -- i
>   return unpack(ret)
> end -- multunpack

it might be interesting to compare the speed of  t[#t+1]=exp versus 
table.insert (t, exp), since it's in the inner loop a small difference could 
be significant.

i guess it should be the same, unless the insert() function uses a different 
way to determine the 'end' of the array.... it was a hot topic in the design 
of 5.1, i don't remember what was the final decision.

-- 
Javier

Attachment: pgpJShnfyJKtd.pgp
Description: PGP signature

Reply | Threaded
Open this post in threaded view
|

Re: Using unpack() twice in a single function call

Luiz Henrique de Figueiredo
> it might be interesting to compare the speed of  t[#t+1]=exp versus 
> table.insert (t, exp), since it's in the inner loop a small difference could 
> be significant.

If you're *really* interested in speed, try also using a local counter,
as below (untested):

 -- Like unpack, but accepts multiple arguments:
 function multunpack(...)
   local ret = {}
   local n = 0
   for i = 1, select("#", ...) do
     for _, rec in ipairs(select(i, ...)) do
       n = n + 1
       ret[n] = rec
     end -- _, rec
   end -- i
   return unpack(ret)
 end -- multunpack

Reply | Threaded
Open this post in threaded view
|

Re: Using unpack() twice in a single function call

Mike Pall-64
In reply to this post by Javier Guerra Giraldez
Hi,

Javier Guerra wrote:
> it might be interesting to compare the speed of  t[#t+1]=exp versus 
> table.insert (t, exp), since it's in the inner loop a small difference could 
> be significant.

http://lua-users.org/lists/lua-l/2005-09/msg00130.html

About the original question: if the length and the number of
tables is fixed it's much faster to use: a[1], a[2], b[1], b[2].
Avoid overdesign when a simple solution fulfills your needs.

Bye,
     Mike

Reply | Threaded
Open this post in threaded view
|

Re: Using unpack() twice in a single function call

Aaron Brown
In reply to this post by Javier Guerra Giraldez
Javier wrote:

it might be interesting to compare the speed of
t[#t+1]=exp versus table.insert (t, exp)

i guess it should be the same,

I think most of the difference in speed comes from the
overhead of the function call.

--
Aaron

Reply | Threaded
Open this post in threaded view
|

RE: Using unpack() twice in a single function call

Framework Studios: Hugo
Hi,

First of all, I really appreciate the quick and meaningful answers to the
unpack() question, thank you!

Second, since we use table inserts a lot in our projects I did some tests on
how the speed of it compares as mentioned by Aaron and Javier. I thought it
would be nice to share the results.

The code for the tests:

function Test1(a)
	for i = 1, 5000 do
		table.insert(a, i)
	end
end

function Test2(a)
	for i = 1, 5000 do
		a[#a + 1] = i
	end
end

function Test3(a)
	for i = 1, 5000 do
		a[i] = i
	end
end

The test was done on an old AMD 900 running Windows XP, the time checked by
QueryPerformanceTimer, running on Lua 5.1 with LuaJIT. The results vary a
bit for several reasons, but still seem clear:

Test 1: 0.0054836575873196
Test 2: 0.0047802170738578
Test 3: 0.0033275177702308

Test 1: 0.0062007885426283
Test 2: 0.004486883059144
Test 3: 0.0032674539834261

Test 1: 0.0065896646119654
Test 2: 0.0048497775569558
Test 3: 0.0028129266574979

Test 1: 0.0052182609215379
Test 2: 0.0065751373767853
Test 3: 0.0039544124156237

Test 1: 0.0055099176242948
Test 2: 0.0050414223223925
Test 3: 0.0026796702295542

Test 1: 0.0059292451478541
Test 2: 0.0052207754924893
Test 3: 0.0027126353234053

Test 1: 0.006284317933023
Test 2: 0.0047106547281146
Test 3: 0.003342604264617

Test 1: 0.0054825400002301
Test 2: 0.0043044574558735
Test 3: 0.0037068957462907

So it seems in some cases using a local counter (Test3) in stead of
table.insert (Test1) can almost half the execution time, and, the difference
between a[#a + 1] and using a local counter also seems significant.

	Thanks again,

			Hugo


-----Original Message-----
From: [hidden email]
[[hidden email] Behalf Of Aaron Brown
Sent: vrijdag 4 augustus 2006 22:14
To: Lua list
Subject: Re: Using unpack() twice in a single function call


Javier wrote:

> it might be interesting to compare the speed of
> t[#t+1]=exp versus table.insert (t, exp)

> i guess it should be the same,

I think most of the difference in speed comes from the
overhead of the function call.

--
Aaron