lua-users home
lua-l archive

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


Hi Tom,

On 2007sep09, Tom Miles <Tom@creative-assembly.co.uk> wrote:
> Okay, so I'm obviously missing something with this. Can anyone explain
> the behaviour from this:
>
>   function test1() return 1, 2 end
>   function test2() return 3, 4 end
>   print(test1(), test2())   --> 1 3 4
>
> I would have expected it to output 1 2 3 4. Why doesn't it?

Let me expand your example a bit:

    f  = function () return 1, 2 end
    f1 = function () return 1    end
    g  = function () return 3, 4 end
    g1 = function () return 3    end
    z  = function () return      end
    n  = function () return nil  end

    a, b = f1(), g1(); print(a, b)   --> 1 3
    a, b = f1(), g();  print(a, b)   --> 1 3
    a, b = f(),  g1(); print(a, b)   --> 1 3
    a, b = f(),  g();  print(a, b)   --> 1 3
    a, b = z(),  g();  print(a, b)   --> nil 3
    a, b = n(),  g();  print(a, b)   --> nil 3

    print(f1(), g1())     --> 1 3
    print(f1(), g())      --> 1 3 4
    print(f(),  g1())     --> 1 3
    print(f(),  g())      --> 1 3 4
    print(n(),  g())      --> nil 3 4
    print(z(),  g())      --> nil 3 4
    print(f(),  n())      --> 1 nil
    print(f(),  z())      --> 1

Note (see the last "print") that functions in Lua can return zero
values too... If Lua had the "splicing behavior" that you were
expecting, then we would have this:

    print(f(),  g())                --> 1 2 3 4  (if we had splicing)
    print(f1(), g())                --> 1 3 4
    print(n(),  g())                --> nil 3 4
    print(z(),  g())                --> 3 4      (if we had splicing)

    a, b = f(),  g();  print(a, b)  --> 1 2      (if we had splicing)
    a, b = f1(), g();  print(a, b)  --> 1 3
    a, b = n(),  g();  print(a, b)  --> nil 3
    a, b = z(),  g();  print(a, b)  --> 3 nil    (if we had splicing)

The reference manual has an impeccably precise description of how Lua
behaves - but it does not explain the rationale. Let me quote from it:
(this is from <http://www.lua.org/manual/5.1/manual.html#2.5>,
slightly abridged) -

    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 as the last (or the only) element of a list
    of expressions, then no adjustment is made (unless the call is
    enclosed in parentheses). In all other contexts, Lua adjusts the
    result list to one element, discarding all values except the first
    one.

       f()                -- adjusted to 0 results
       g(f(), x)          -- f() is adjusted to 1 result
       g(x, f())          -- g gets x plus all results from f()
       a,b,c = f(), x     -- f() is adjusted to 1 result (c gets nil)

       a,b,c = x, f()     -- f() is adjusted to 2 results
       a,b,c = f()        -- f() is adjusted to 3 results
       return f()         -- returns all results from f()
       return x,y,f()     -- returns x, y, and all results from f()
       {f()}              -- creates a list with all results from f()
       {f(), nil}         -- f() is adjusted to 1 result

    An expression enclosed in parentheses always results in only one
    value. Thus, (f(x,y,z)) is always a single value, even if f
    returns several values. (The value of (f(x,y,z)) is the first
    value returned by f or nil if f does not return any values.)

If Lua used the splicing behaviour by default then people would have
to adjust subexpressions to one result in their programs - with "()"s
- very often... but it turned out that people don't usually need
splicing so much, so the authors of Lua decided to that it would be
better to make the comma in expressions an "adjusting to 1 result"
operator instead of a splicing operator...

  Cheers,
    Eduardo Ochs
    http://angg.twu.net/
    eduardoochs@gmail.com


P.S.: any suggestions of a good syntax for a "splicing comma"? It just
occurred to me (for Lispy reasons) that "@" could be nice -

    print(f(), g())   --> 1 3 4
    print(f() @ g())  --> 1 2 3 4

but I'm not going to write the patch...