tags:

views:

233

answers:

3

It seems that in Lua, I can either pass vararg on to another function, or take a peek at them through arg, but not both. Here's an example:

function a(marker, ...)
  print(marker)
  print(#arg, arg[1],arg[2])
end

function b(marker, ...)
  print(marker)
  destination("--2--", ...)
end

function c(marker, ...)
  print(marker)
  print(#arg, arg[1],arg[2])
  destination("--3--", ...)
end


function destination(marker, ...)
  print(marker)
  print(#arg, arg[1],arg[2])
end

Observe that a only looks at the varargs, b only passes them on, while c does both. Here are the results:

>> a("--1--", "abc", "def")
--1--
2   abc def


>> b("--1--", "abc", "def")
--1--
--2--
2   abc def


>> c("--1--", "abc", "def")
--1--
test.lua:13: attempt to get length of local 'arg' (a nil value)
stack traceback:
    ...test.lua:13: in function 'c'
    ...test.lua:22: in main chunk
    [C]: ?

What am I doing wrong? Am I not supposed to combine the two? Why not?

+1  A: 

You can use select() to examine ... without resorting to the arg table:

firstarg  = select(1, ...)
secondarg = select(2, ...)

and so on.

I'm not sure why you're having trouble combining the two, however - in my experience intermixing them (and different operations on either) hasn't been a problem.

Amber
Hm, if you think this shouldn't happen then I guess it's a bug.
romkyns
+5  A: 

The use of arg is deprecated. Try this:

function a(marker, ...)
  print(marker)
  print(select('#',...), select(1,...), select(2,...))
end

function b(marker, ...)
  print(marker)
  destination("--2--", ...)
end

function c(marker, ...)
  print(marker)
  print(select('#',...), select(1,...), select(2,...))
  destination("--3--", ...)
end

function destination(marker, ...)
  print(marker)
  print(select('#',...), select(1,...), select(2,...))
end

Here's what you get:

> a("--1--", "abc", "def")
--1--
2   abc def
> b("--1--", "abc", "def")
--1--
--2--
2   abc def
> c("--1--", "abc", "def")
--1--
2   abc def
--3--
2   abc def
>
Doug Currie
`print(select('#',...), select(1,...), select(2,...))` doesn't work how you think it does. select just cuts off the first n arguments, leaving the rest there: that is actually the same as `print(select('#',...), ...)`.You can either wrap each argument in parenthesis; or use an array: function a(m,...) local arg = { n = select("#",...), ... } print(arg.n,arg[1],arg[2]) end
daurnimator
@daurnimator, You are connect that select(N,...) returns all the values starting with argument N. This only matters for the last argument passed to print. "If a vararg expression is used inside another expression or in the middle of a list of expressions, then its return list is adjusted to one element. If the expression is used as the last element of a list of expressions, then no adjustment is made (unless that last expression is enclosed in parentheses)." In this case it doesn't matter (the last argument in the print call happens to to be passed only one value since it is the last of ...).
Doug Currie
+3  A: 

For the number of arguments, you need select. To look at them, you can do this:

local first,second,third = ...
lhf