A Lua puzzle

A conversation with Marc Bradshaw about a Lua puzzle I found myself in.

Lua 5.2.1  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> function x() return 'a','b','c' end
> print(x())
a b c
> print(x(),'d')
a d

A variant of this (table.unpack shenanigans) screwed me for about half an hour this morning. I’m sure there’s a logical explanation, but I’m not seeing it.

Could the second print be prototyping as a 2 element list and then dumping the second and third elements of the first argument?

I wondered that, though Lua doesn’t have any concept of prototypes as such. But if that’s the case, why does the first work?

Its not just print() though - where this actually bit me was doing the equivalent of: t = { x(), 'd' }. This exhibits the same behaviour - { x() } expands to { 'a', 'b', 'c' } whereas { x(), 'd' } expands to { 'a', 'd' }.

What happens if you have a function y() which returns 'd' instead of using the literal?

Interesting thought, and interesting results:

Lua 5.2.1  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> function x () return 'a','b','c' end
> function y () return 'd' end
> print(x(),y())
a d

But then:

> function y () return 'd','e','f' end
> print(x(),y())
a d e f
> print(x(),y(),x())
a d a b c

So it takes the first value from each of the expanded arguments except for the last one, where it takes them all.

Interesting….

Could it be an optimisation side-effect?

Turns out its documented: http://www.lua.org/manual/5.2/manual.html#3.4

The why isn’t exactly clear. The only possible answer I’ve found is that allowing it would make the following unclear:

a,b,c = f(), g()

in that you don’t know whether the values you got back came from f() or g(). I can work around this with:

a = f()
b,c = g()

This looks like an interesting library to work around it: http://luarocks.org/repositories/rocks/#vararg

But of course I could have written something similar in C myself. That’s not quite the point.