lua-users home
lua-l archive

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


Alexander Gladysh wrote:
On Tue, Nov 25, 2008 at 7:19 AM, KHMan <...> wrote:
Alexander Gladysh wrote:
On Mon, Nov 17, 2008 at 3:38 PM, Peter Cawley <...> wrote:
[snip][snip][snip][snip]
Trouble is, does this pattern ever appear in normal code? I find it
difficult to believe that calling a function that returns a function to be
called, and so on, chained in this manner, could happen in real-world code.

Well, it does in mine. I often use this idiom for heavy concatenation
code (for one thing, you may easily replace buffering cat() with
io.write()):

local buf = {}

local function cat(s)
  buf[#buf + 1] = s
  return cat
end

local function test()
  cat "one" "two" "four" "five"
end

Apologies for one more posting...

I'm not so sure "Chaining calls use less resources" in an earlier posting is strictly correct. When comparing two implementations for cat(s),

local buf; local function cat(s) buf[#buf + 1] = s return cat end
local buf; local function cat(s) buf[#buf + 1] = s end

Chained function calls would require

function <stdin:1,1> (8 instructions, 32 bytes at 0x680f78)
1 param, 3 slots, 2 upvalues, 1 local, 1 constant, 0 functions
        1       [1]     GETUPVAL        1 0     ; buf
        2       [1]     GETUPVAL        2 0     ; buf
        3       [1]     LEN             2 2
        4       [1]     ADD             2 2 -1  ; - 1
        5       [1]     SETTABLE        1 2 0
        6       [1]     GETUPVAL        1 1     ; cat
        7       [1]     RETURN          1 2
        8       [1]     RETURN          0 1

versus

function <stdin:1,1> (6 instructions, 24 bytes at 0x680f78)
1 param, 3 slots, 1 upvalue, 1 local, 1 constant, 0 functions
        1       [1]     GETUPVAL        1 0     ; buf
        2       [1]     GETUPVAL        2 0     ; buf
        3       [1]     LEN             2 2
        4       [1]     ADD             2 2 -1  ; - 1
        5       [1]     SETTABLE        1 2 0
        6       [1]     RETURN          0 1

Since CALL consumes the register holding the closure object, somebody must provide it, either the caller or the callee. In chaining, the callee provides it. In the caller, one MOVE is saved, but it is simply moved elsewhere, since it looks like the same number of instructions is executed (with GETUPVAL substituting for MOVE). But chain_upval appears to be slightly faster in generic Lua; analyzing why this is so would require quite a bit of effort I suppose.

--
Cheers,
Kein-Hong Man (esq.)
Kuala Lumpur, Malaysia