lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi,

David Given wrote:
> How does ... work, anyway? Does it actually *copy* the data from its original 
> place on the stack, or does it do something smarter?

The call frame for a fixarg function looks like this:

ci->func --> func
ci->base --> fixargs
             locals
ci->top  -->

The call frame for a vararg function in Lua 5.1 looks like this:

ci->func --> func
             setnil'ed fixargs
             varargs
ci->base --> moved fixargs
             locals
ci->top  -->

When calling a vararg function the fixargs are moved upwards after
the last vararg. The remaining gap is cleared with nils (closing
that gap wouldn't pay off since most vararg functions have only
very few fixargs). The varargs themselves are not moved.

Evaluating ... aka OP_VARARG _does_ copy the varargs up to new stack
slots, i.e. f(...) copies them once.

Tailcalls (return f(...)) or vararg returns (return ...) effectively
copy them twice because the slots need to be moved down, too.

> I ask because I found an interesting idiom recently for doing work with large 
> amounts of constant data --- it was while writing the BF compiler, oddly 
> enough --- reminiscent of some of the structures used in functional 
> programming languages:
> 
> function process(item1, item2, ...)
> 	dosomethingwith(item1, item2)
> 	return process(...)
> end

This will copy them twice on each recursion. The maximum needed
stack space is twice the number of fixargs+varargs (plus other
overhead) since you are using a tail call.


A similar idiom can be used to both capture and pass on a variable
number of _return_ values:

local function helper(ok, ...)
  if not ok then print("ERROR:", ...) end
  return ok, ...
end

local function printpcall(...) -- Dito for coroutine.resume().
  return helper(pcall(...))
end


I guess in practice most varargs will have less than 10 elements
on average. I wouldn't worry too much about efficiency then.

A table would be more appropriate in case one wants to pass
hundreds or thousands of objects as varargs.

Bye,
     Mike