lua-users home
lua-l archive

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


Hello all,

today I came across something extremely scary.  For the past year or
so I had been under the impression function execution continued past
any `return something' statement.  Whereas writing code like this:

function whatever()
  if condition then
    return 1
  end
  return 2
end

Resulted in either `return 1, 2' or `return 2' upon completion of the
function.  I could have sworn that a few people had complained about
this behavior when I would give them advice on how to write the flow
of their control in their functions.  However, I recently tested this
for someone when he asked me about it, only to find out return acted
like it did in any "sane" language.  When I asked about it in #lua on
Freenode another person said it was what sane languages did.  However,
while the inconsistency of my memory is in question and while I am
shocked to think that I wrote my functions without ever relying on the
behavior of what I was misled into thinking, I believe this would be
an ideal behavior for Lua.  My understanding of coroutines is that the
function temporarily yields control to the calling block of code with
it's returned value and then resumes execution.  What I am talking
about here is that every return statement instead pushes the value
it's returning onto the Lua stack, and then the stack as a whole is
returned at the end of the function.  When I discussed *this* behavior
in #lua someone said I should return a table of the parameters
instead.  However, I don't believe this would be suitable considering
the unnecessary memory used to create this table which is only going
to be unpacked at the end of the function anyway.  What I am talking
about is theoretical code like this:

return condition and 1 or 2, 3, condition and 4 or 5

The problem I see with this is when we imagine that each condition can
span many lines and cannot be concisely represented with Lua's
equivalent of a ternary operator.  When we know what value will be
returned constantly on every function call, in this case 3, but not
what the first or last conditional will return.  This is why I believe
it would be a great idea to instead be able to write something like
the first function I showed.  In this false reality I had going for
the past year, I had always looked down on functions that were written
like `whatever()' that I showed above, because it would always return
2 (so I thought).  This was the reason that people (so I had thought)
did not like how Lua's return did not return right away and cease
execution of the function.  All that would change by modifying the
behavior of return, is we would be structuring our functions
differently to make use of else, once again:

function whatever()
  if condition then
    return 1
  else
    return 2
  end
end

The beauty of these stack-based returns is that hopefully it would
allow for another data type to be exploited in Lua, instead of relying
on tables to represent sparse arrays.

It would be great (in my opinion) if we could do things like:

for x in function () return 1, 2, 3, 4, 5 end do
  print(x)
end

Obviously no one would write this exact code but the idea here is that
the anonymous function would execute before the loop is started and
each iteration of the loop would take next returned value from this
"stack".  And let's pretend that was return 3, 2, 7, 99, 182, so I
won't get comments saying you could do this with the usual for loop
incrementing x.

The biggest issue I see with this would be finding a way to represent
an array instead of a table when you:

local bleh = assignallreturnedvalues()

I therefore propose this syntax:

local bleh = | assignallreturnedvalues() |

Whereas if this were a table it would be using the brackets ({})
enclosed around the function call.

Hopefully this would allow for "saner" array handling instead of
hitting pitfalls with holes in ..."iterable" tables. (ipairs())

-----------------------

In conclusion, I have no patches, I have no test cases, this is just a
crazy idea that I really love and thought I would share.  What I
wanted to avoid was:

function whatever()
  local t = {}
  if multi_line conditional then
    table.append(t, 4)
  end
  table.append(t, 'potato')
  if multi_line conditional then
    table.append(t, { 'cat', 'dog', 'horse' })
  end
end

PS: I'm pretty sure this idea sprung from how values are pushed onto
the Lua stack and then the number of elements is returned in exposed C
functions from the CAPI.

I hope you enjoyed reading.