lua-users home
lua-l archive

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

On Mon, Sep 23, 2013 at 12:20 PM, Andrew Starks <> wrote:
I have many setter methods that handle properties that represent an
inventory of one or more objects of the same class (to borrow from

So that I don't need to write a "set_prop" and "set_props" function, I
write this quite a bit:

local function f(arg, ...)
    if (...) then
        return arg, f(...)
        return arg

A more compact variant doesn't work:

local function f2(arg, ...)
    return arg, (...) and f2(...)

...for more than two recursions.

It's not a big deal, at all, but if there was some way to get closer
to the second example, and still have it work for n arguments, I'd
like to know it.



In a couple of my apps I've run into a similar problem, when I want to implement callbacks. The idea is, any module can register a callback on a certain event, and every registered callback will be called in order; each function is expected to return its arguments, but could modify them, or return nil to prevent the rest of the functions in the chain from being called. This is used for filtering events.

The only generic way I've found to implement this ends up looking kinda gross:
local function concat_args(args)
    --this function is used to build argument lists for error messages
    --it's similar to table.concat but uses args.n instead of #args
    --and wraps strings in quotes so types are more apparent
    --in the output.
    local str = ''

    for i = 1, args.n do
        local v = args[i]
        if type(v) == 'string' then v = '"' .. v .. '"'
        else v = tostring(v)
        str = str .. v .. ', '

    return str:sub(1, -3) --strip last ', '

function call_callbacks(event, ...)
    local args = table.pack(...)
    for i, mdl in ipairs(modules) do
        if mdl[event] then

            local ret = table.pack(xpcall(
                mdl[event], debug.traceback, mdl,
                table.unpack(args, 1, args.n)))

            --table.remove only deals with sequences (1...#t),
            --so we have to do this manually instead.
            local ok = ret[1]
            for i = 1, ret.n do ret[i] = ret[i+1] end
            ret.n = ret.n - 1

            if ok then
                args = ret
                if not ret[1] then break end
            else log.error("Module '%s' error in '%s': %s\n(params: %s)",
                mdl._name, event, ret[1], concat_args(args))
    return table.unpack(args, 1, args.n)

Between the varargs and the xpcall it's a bit awkward (and quite a bit of code) to receive an arbitrary number of return values and then pass them on to another function or return them. (It'd be even more awkward in Lua 5.1 where you don't have table.pack; {...} won't suffice as the list can contain nils.)

Sent from my Game Boy.