Why a label after a return cause syntax error? - lua

With Lua 5.4:
function f()
return 1
::LABEL::
end
print(f())
I got error:
lua: _.lua:3: 'end' expected (to close 'function' at line 1) near '::'
while
function f()
if true then return 1 end
::LABEL::
end
print(f())
works fine.
I don't understand that error.

Labels syntactically are statements. This can be seen from the grammar in the reference manual:
stat ::= label | ...
A return statement is syntactically required to be the last statement in a block:
block ::= {stat} [retstat]
The following Lua code would throw a similar syntax error:
function f()
return
x = 1
end
simply because the assignment x = 1, a statement just like labels, comes after the return. Simply put, return ... must be followed by end. The rationale for this presumably is that Lua doesn't want to allow "dead code" (although this isn't really valid for labels); IIRC it also resolves a syntactical ambiguity.
If you wrap the return in a block, the syntax error is fixed - the return now is the last statement in the block, there are no "dead statements" after it:
function f()
if 1 then return end -- return is followed by end - all is well (syntactically)!
x = 1 -- this is still dead code (semantically)
end
Lua can't and won't semantically analyze your code to determine that the assignment to x is still dead code.
This is used for quick'n'dirty insertion of early returns during debugging: You can simply wrap them in do ... end:
function f()
do return end -- syntactically valid, equivalent to commenting out the rest of the function
x = 1
end

Related

Strange behavior caused by debug.getinfo(1, "n").name

I learned how to get the function name inside a function by using debug.getinfo(1, "n").name.
Using this feature, I found out the strange behavior in Lua.
Here's my code:
function myFunc()
local name = debug.getinfo(1, "n").name
return name
end
function foo()
return myFunc()
end
function boo()
local name = myFunc()
return name
end
print(foo())
print(boo())
Result:
nil
myFunc
As you can see, the function foo() and boo() calls the same function myFunc() but they return different results.
If I replace debug.getinfo(1, "n").name with other string, they return the same results as expected but I don't understand the unexpected behavior caused by using the debug.getinfo().
Is it possible to correct myFunc() function so calling both foo() and boo() functions return the same result?
Expected result:
myFunc
myFunc
In Lua, any return statement of the form return <expression_yielding_a_function>(...) is a "tail call". Tail calls essentially don't exist in the call stack, so they take up no additional space or resources. The function you call effectively gets erased from the debug information.
Is it possible to correct myFunc() function so calling both foo() and boo() functions return the same result?
Um... yes, but before I tell you how, allow me to try to convince you not to do this.
As previously mentioned, tail calls are part of the Lua language. The removal of tail calls from the stack is not an "optimization" any more than it is an "optimization" for a for loop to exit when you use break. It is a part of Lua's grammar, and Lua programmers have just as much a right to expect a tail call to be a tail call as they have the right to expect break to exit loops.
Lua, as a language, specifically states that this:
local function recursive(...)
--some terminating condition
return recursive(modified_args)
end
will never, ever, run out of stack space. It will be just as stack space efficient as performing a loop. This is a part of the Lua language, just as much a part of it as the behavior of for and while.
If a user wants to call your function via a tail call, that is their right as the user of a language that makes tail calls a thing. Denying users of a language the right to use the features of that language is rude.
So don't do it.
Furthermore, your code suggests that you are attempting to rely on functions having names. That you're doing something significant and meaningful with those names.
Well, Lua is not Python; Lua functions do not have to have names, period. As such, you should not write code that meaningfully relies upon the name of a function. For debugging or logging purposes, fine. But you should not break user expectations just for debugging and logging. So if the user made a tail call, just accept that's what the user wanted and that your debugging/logging will suffer slightly.
OK, so, do we agree that you shouldn't do this? That Lua users have the right to tail calls, and you don't have the right to deny them? That Lua functions are not named and you shouldn't write code that requires them to maintain a name? OK?
What follows is terrible code that you should never use! (in Lua 5.3):
function bypass_tail_call(Func)
local function tail_call_bypass(...)
local rets = table.pack(Func(...))
return table.unpack(rets, rets.n)
end
return tail_call_bypass
end
Then, simply replace your real function with the return of the bypass:
function myFunc()
local name = debug.getinfo(1, "n").name
return name
end
myFunc = bypass_tail_call(myFunc)
Note that the bypass function has to build an array to hold the return values, then unpack them into the final return statement. This obviously requires additional memory allocations that don't have to happen in regular code.
So there's another reason not to do this.
You can run your code through luac -l -p
...
function <stdin:6,8> (4 instructions at 0x555f561592a0)
0 params, 2 slots, 1 upvalue, 0 locals, 1 constant, 0 functions
1 [7] GETTABUP 0 0 -1 ; _ENV "myFunc"
2 [7] TAILCALL 0 1 0
3 [7] RETURN 0 0
4 [8] RETURN 0 1
function <stdin:10,13> (4 instructions at 0x555f561593b0)
0 params, 2 slots, 1 upvalue, 1 local, 1 constant, 0 functions
1 [11] GETTABUP 0 0 -1 ; _ENV "myFunc"
2 [11] CALL 0 1 2
3 [12] RETURN 0 2
4 [13] RETURN 0 1
Those are the two function that are of interest to us: foo and boo
As you can see, when boo calls myFunc, it's just a normal CALL, so nothing interesting there.
foo, however, does something called a tail call. That is, the return value of foo is the return value of myFunc.
What makes this kind of call special is that there is no need for the program to jump back into foo; once foo calls myFunc it can just hand over the keys and say "You know what to do"; myFunc then returns its results directly to where foo was called. This has two advantages:
The stack frame of foo can be cleaned up before myFunc is called
once myFunc returns, it doesn't need two jumps to return to the main thread; only one
Both of those are insignificant in examples like yours, but once you have a chain of lots and lots of tail calls, it becomes significant.
The downside of this is that, once the stack of foo gets cleaned up, Lua also forgets all the debugging information associated with it; it only remembers that myFunc was called as a tail call, but not from where.
An interesting side note, is that boo is almost also a tail call. If Lua didn't have multiple return values, it'd be exactly identical to foo, and a smarter compiler like LuaJIT might compile it to a tail call. PUC Lua won't though, since it needs a literal return some_function() to recognize the tail call.
The difference is that boo only returns the first value returned by myFunc, and while in your example, there will only ever be one, the interpreter can't make that assumption (LuaJIT might make that assumption during JIT compilation, but that's beyond my understanding)
Also note that, technically, the word tail call just describes a function A directly returning the return value of another function B.
It often gets used interchangeably with tail call optimization, which is what the compiler does when it re-uses the stack frame and turns the function call into a jump.
Strictly speaking, C (for example) has tail calls, but it has no tail call optimization, meaning something like
int recursive(n) { return recursive(n+1); }
is valid C code, but will eventually cause a stack overflow, while in Lua
local function recursive(n) return recursive(n+1) end
will just run forever. Both are tail calls, but only the second gets optimized.
EDIT: As always with C, some compilers may, on their own, implement tail call optimization, so don't go around telling everyone that "C never ever does it"; it's just not a requried part of the language, while in Lua it's actually defined in the language specification, so it's not Lua until it has TCO.
This is a result of tail call optimisation, which Lua does.
In this case, Lua translates the function call into a "goto" statement, and does not use any extra stack frame to perform the tail call.
You can add traceback statement to check it:
function myFunc()
local name = debug.getinfo(1, "n").name
print(debug.traceback("Stack trace"))
return name
end
Tail call optimisation happens in Lua when you return with a function call:
-- Optimized
function good1()
return test()
end
-- Optimized
function good2()
return test(foo(), bar(5 + baz()))
end
-- Not optimised
function bad1()
return test() + 1
end
-- Not optimised
function bad2()
return test()[2] + foo()
end
You can refer to the following links for more information:
- Programming in Lua - 6.3: Proper Tail Calls
- What is tail call optimisation? - Stack Overflow

What does this function return

function f(...)
return ...
end
And I call it like this:
f()
Example
a = f()
print(a) -- echoes 'nil', same as print(nil)
But
print(f()) -- echoes newline, same as print(), that is, no args
t = {f()} -- same as t = {}
So, what does f() return?
Update: did not know that functions can return 'void', found this http://lua-users.org/lists/lua-l/2011-09/msg00289.html meanwhile.
It returns all parameters you called it with.
f() -- has no parameter, returns nothing
If you do an assignment with less values than you have variables, i.e.
local a, b = 3
local c
Then that'll just end up with b and c being nil.
On the other hand, this would all do something:
f(1) -- returns 1
f(1, 2, 3) -- returns 1, 2 and 3
local t = {f(1, 2, 3)} -- table with the values 1, 2 and 3
The answer regarding the type could be the output of this command:
print(type(f()))
In this case, it prints:
bad argument #1 to 'type' (value expected)
So, a value is expected, but there is no value. => It returns nothing (void).
So, it's a normal behaviour to have: t = {f()} <=> t = {}
Regarding the assignment, Lua assigns by default the nil value if there is no value.
I found that Lua function can return 'nothing', not even a nil. In this case, f() returns nothing. Using nothing (without assignment) results in zero arguments in another function call(like print(f()) or in table constructor({f()}).
print(a) echoed nil because a had no assigned value, print(any_name) will echo nil aswell.

'end' expected (to close 'function' at line 1) near '<eof>'

I get this error
[ERROR] lua/autorun/donor_guns.lua:4: 'end' expected (to close 'function' at line 1) near '<eof>'
1. unknown - lua/autorun/donor_guns.lua:0
when running this script
hook.Add( "PreDrawViewModel", "ReplaceCrowbar", function( vm, ply, weapon )
if ( ply:GetNWString( "usergroup" ) == "donor" and weapon = "weapon_ttt_caliburn" then
vm:SetModel( "models/tiggomods/weapons/SATBK/v_Caliburn.mdl" )
end
any help?
You are missing a 'end' closure to your function declaration ,a ')' to end your function call, a '=' to your second equality test and '(' after if is useless and not closed. It should be :
hook.Add( "PreDrawViewModel", "ReplaceCrowbar",
function( vm, ply, weapon )
if ply:GetNWString( "usergroup" ) == "donor" and weapon == "weapon_ttt_caliburn" then
vm:SetModel( "models/tiggomods/weapons/SATBK/v_Caliburn.mdl" )
end
end
)
You're short of an end, as the compiler so clearly tells you.
A lua conditional statement looks like this:
if <condition> then
<statements...>
end
And a function is like this
function foo(params)
<statements...>
end
Also, your brackets don't match.
I know this is an old thread. Just had the same problem and wanted to add another possible point of failure - check your "if-else" statements, namely your "elseif"s. I have just spent half an hour trying to find "missing" end, because "else if" was written with a space, which apparently looks like a totally separate IF statement to the Lua -_-

Hello metatable.__len world

A beginner's question about Lua and metatables, with a example as simple as an Hello‑World, involving the len event, which unfortunately does not returns the expected result (I'm using Lua 5.1 installed from Ubuntu's official repository).
The case
Here is the example:
Test_Type = {};
function Test_Type.__len (o)
return 1;
end;
function new_test ()
local result = {};
setmetatable(result, Test_Type);
return result;
end;
do
local a_test = new_test();
print (#a_test);
print(getmetatable(a_test).__len(a_test));
end;
And the result I get:
0
1
I was expecting the first print statement to display 1, but it displays 0, to my big surprise.
What did I missed?
According to Lua Reference Manual — Metatables and Metamethods, the # is equivalent to this:
function len_event (op)
if type(op) == "string" then
return strlen(op) -- primitive string length
else
local h = metatable(op).__len
if h then
return (h(op)) -- call handler with the operand
elseif type(op) == "table" then
return #op -- primitive table length
else -- no handler available: error
error(···)
end
end
end
So print (#a_test); and print(getmetatable(a_test).__len(a_test)); should result into the same, isn't it?
By the way, why is the above excerpt from the Reference Manual refers to metatable(op) while it should be getmetatable(op)? At least I've tried print(metatable(a_test).__len(a_test));, and it ends into an error.
Answer
As Nneonneo noticed, this is an issue with the Lua version in use. Lua 5.2 seems to be required for the above to work.
From http://lua-users.org/wiki/LuaFaq:
Why doesn't the __gc and __len metamethods work on tables?
__len on tables is scheduled to be supported in 5.2. See LuaFiveTwo.
Since you're using 5.1, __len on tables does not work. Indeed, running your code on Lua 5.2 produces
1
1
as expected.

Block is unfinished

This code fragment is compiled:
let test =
let x = 1
printfn "%A" x
If the last line is removed, there is the following compilation error:
error FS0588: Block following this 'let' is unfinished. Expect an expression.
What does this message mean? In C#/C++ I would expect the "Unused variable" warning in such situation, but F# gives something different.
In F#, a function has to bind a name to a value.
The printfn statement has a return value, and this is ultimately what gets bound to test.
Without the printfn statement you only have a statement binding the value 1 to x. The compiler will be expecting something to bound to test. Because the test function stops at this point, this is why you are seeing the compiler errror.
If you want your function just to do stuff (possibly with side effects), you should end your function with ()

Resources