Forward define a function in Lua?

20,500

Solution 1

Lua is a dynamic language and functions are just a kind of value that can be called with the () operator. So you don't really need to forward declare the function so much as make sure that the variable in scope when you call it is the variable you think it is.

This is not an issue at all for global variables containing functions, since the global environment is the default place to look to resolve a variable name. For local functions, however, you need to make sure the local variable is already in scope at the lexical point where you need to call the value it stores, and also make sure that at run time it is really holding a value that can be called.

For example, here is a pair of mutually recursive local functions:

local a,b
a = function() return b() end
b = function() return a() end

Of course, that is also an example of using tail calls to allow infinite recursion that does nothing, but the point here is the declarations. By declaring the variables with local before either has a function stored in it, those names are known to be local variables in lexical scope of the rest of the example. Then the two functions are stored, each referring to the other variable.

Solution 2

You can forward declare a function by declaring its name before declaring the actual function body:

local func1
local func2 = function()
  func1()
end
func1 = function()
  --do something
end

However forward declarations are only necessary when declaring functions with local scope. That is generally what you want to do, but Lua also supports a syntax more like C, in which case forward declaration is not necessary:

function func2()
  func1()
end
function func1()
  --do something
end

Solution 3

Testing under the embedded lua in Freeswitch, forward declaration does not work:

fmsg("CRIT", "It worked.")
function fmsg(infotype, msg)
   freeswitch.consoleLog(infotype,  msg .. "\n")
end

result:

[ERR] mod_lua.cpp:203 /usr/local/freeswitch/scripts/foo.lua:1: attempt to call global 'fmsg' (a nil value)

Reversing the order does (duh) work.

Solution 4

To comprehend how forward referencing in Lua works compared to C, you must understand the a fundamental difference between C compilation and the Lua execution.

  • In C, forward referencing is a compile time mechanism. Hence if you include a forward declaration template in a C module then any of your code following will employ this template in compiling the call. You may or may not include the function implementation in the same module, in which case both declarations must be semantically identical or the compiler will error. Since this is a compile time construct, the compiled code can be executed in any order.

  • In Lua, forward referencing is runtime mechanism, in that the compiled function generates a function prototype internally within the code, but this is only accessible as a runtime Lua variable or value after the execution has passed over the declaration creating a Lua closure. Here the declaration order within the source is immaterial. It is the execution order that is important: if the closure hasn't been bound to the variable yet, then the execution will throw a "nil value" exception.
    If you are using a local variable to hold the function value, then normal local scoping rules still apply: the local declaration must precede its use in the source and must be within scope, otherwise the compiler will compile in the wrong global or outer local reference. So forward referencing using locals as discussed in other answer will work, but only if the Protos are bound to closures before the first call is executed.

Share:
20,500

Related videos on Youtube

Elliot Bonneville
Author by

Elliot Bonneville

Full-stack developer with a focus on building single-page web apps with TypeScript, React and Node.js. Also passionate about design systems and helping SaaS startups improve their revenue through digital marketing. Currently looking for new contracts for Q1 and Q2 2020.

Updated on July 09, 2022

Comments

  • Elliot Bonneville
    Elliot Bonneville almost 2 years

    How do I call a function that needs to be called from above its creation? I read something about forward declarations, but Google isn't being helpful in this case. What is the correct syntax for this?

  • Elliot Bonneville
    Elliot Bonneville almost 13 years
    Okay, thanks. I managed to figure it out on my own, but this answer was useful nonetheless.
  • RBerteig
    RBerteig almost 13 years
    Actually, your first example doesn't do what you think it does since the second local func1 is declaring a new variable of that name and leaves the first func1 orphaned and still set to nil.
  • LuaWeaver
    LuaWeaver almost 10 years
    Your second example is bad, too, because naively calling "func2" from below func1 would work, but not because of any sort of "forward declaration". Rather, func1 is declared in the global environment (_G), and when func2 looks up func1, it checks _G. That means that func1 is declared before func2 is run and thus when it checks _G, it works. Throwing a func2 call immediately after func2 is defined results in an error... because func1 isn't declared/defined.
  • jhocking
    jhocking almost 10 years
    That's why I said "However forward declarations are only necessary when declaring functions with local scope". In other words, I was explicitly saying the second example doesn't use forward declaration.