Home Global and local recursive functions in lua
Reply: 2

Global and local recursive functions in lua

esgaldir
1#
esgaldir Published in 2018-01-11 14:32:07Z

I am very new to lua and I would like to understand following behaviour.

When I try to run following recursion function:

local func = function ( n )
  if n == 1 then return 1
  else return n * func( n - 1 )
  end
end

print( func( 5 ) )

The program will fail with error:

lua: main.lua:16: attempt to call a nil value (global 'func')
stack traceback:
main.lua:16: in local 'func'
main.lua:38: in main chunk
[C]: in ?

which is ok, since according to the explanation, local version of func variable is not known yet so it tries to call the global one. But when I delete local keyword, following code works correctly?

func = function ( n )
  if n == 1 then return 1
  else return n * func( n - 1 )
  end
end

print( func( 5 ) )

Program prints 120 as result, but global func was never initialized or used before. How is it possible, that this does not throw error as well? Isn't the second example referencing to global func as it does in the first one?

Vlad
2#
Vlad Reply to 2018-01-11 15:06:42Z

Isn't the second example referencing to global func as it does in the first one?

It is :)

You see, it doesn't matter if value exists or not when you compile new function. It doesn't check the value stored in the func variable, instead it will look it up every time the call is made. The only important thing is variable's visibility. If the variable isn't visible in local scope, then it's considered global, and will be looked up in the global environment table. For more details see Lua manual, chapter 3.5 – Visibility Rules

The first example didn't work because local func variable isn't visible until complete expression is calculated. That's why the first example breaks, trying to call missing global variable.

If you want that func to be local, declare the variable, and then assign it. Like:

local func
func = function ( n )
  if n == 1 then return 1
  else return n * func( n - 1 )
  end
end

print( func( 5 ) )

Probably it will be easier to use Lua's syntactic sugar for this cases:

local function func( n )
  if n == 1 then return 1
  else return n * func( n - 1 )
  end
end

print( func( 5 ) )

It will be translated exactly to the same sequence of declaring variable, and then assigning it.

This time the func variable will be visible to new function(n), so it will read value to call from that specific upvalue.

Note that it's still possible to "break" the function by assigning something different into func variable later. Functions (as any other value) in Lua doesn't have names, only variables do. So calls to functions isn't hardcompiled, the function value to call is always fetched from the variable, before each call.

Tom Blodget
3#
Tom Blodget Reply to 2018-01-13 12:16:13Z

@Vlad answers the question well. A couple points about the question for clarity:

  1. Functions are values so "global function" as in the title doesn't sense by itself without the context of the question.

  2. Variable binding is the process by which the compiler maps an identifier in the code to a variable. Questions about variable binding typically come up regarding recursive functions but the binding rules are simpler and more general. They don't have anything to do with recursion, function definitions or even local vs global. Nonetheless, the syntactic sugar for function definition statements can confuse the issue.

For example:

local x = x + 1 

x in the expression is not the x being created. Which variable it is depends on any code above. It could be a local declared in a statement block or as a function parameter. Such a declaration could be in the same block or function definition or above in an outer one. Global is just the fallback.

Obviously, if local wasn't used in the example above, the same name would be bound to same variable.

 y = y + 1

Both y names are the same variable but, as above, which variable is determined by other code.

This function definition statement is similar:

 function f() end

If a local f is in scope then that is the variable the compiler binds "f" to, otherwise "f" in the global environment.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.31313 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO