4

I have two functions that occasionally call each other, and they are local to a module that uses them to build another function. The module is somewhat similar to this piece of code:

local function iseven(n)
    if n == 1 then
        return false
    else
        return isodd(n - 1)
    end
end

local function isodd(n)
    if n == 1 then
        return true
    else
        return iseven(n - 1)
    end
end

local evenOrOdd = function(n)
    return iseven(n) and "Even" or "Odd"
end

return evenOrOdd

The problem is, when calling evenOrOdd from another file I get the error attempt to call global 'isodd' (a nil value).

I noticed that this doesn't happen if I set iseven to global, but I would like to keep them local to my module.

I even tried putting a dummy function declaration (local function isodd() end) before the line where iseven is declared. I also tried inserting just local isodd in the place of the dummy function declaration, but in both ways it doesn't work and I get different kind of errors.

I know this is because Lua has closures and when iseven is declared it catches the actual value of isodd, which is either nil or the dummy function, and modifying it after doesn't count, but is there a way to bypass this?

user6245072
  • 2,051
  • 21
  • 34
  • 2
    Example of forward declaration in Lua: `local f; local function g() return f() end; function f() return g() end` – Egor Skriptunoff Jul 21 '16 at 11:19
  • @Egor Skriptunoff oh right. As I said in the question, I tried it. But it seems I forgot to delete `local` before `function isodd(n)` and I got the `attempt to call upvalue 'isodd' (a nil value)` error. Thanks. – user6245072 Jul 21 '16 at 11:31
  • The error message for the code you gave should be `attempt to call global 'isodd' (a nil value)`, which should explain what happened. – lhf Jul 21 '16 at 12:30
  • Be careful about carrying the concept of "forward declaration" over from other languages. There is no requirement have an "actual declaration" later. In Lua, only local variables (including parameters) are declared. A function is a value created at runtime from a function definition when an expression containing it executed.Such a value is often assigned to a variable. (The `function ()` syntax is shorthand.) Again, functions are not declared. – Tom Blodget Jul 21 '16 at 16:36

3 Answers3

5

The problem is that the call to isodd in iseven uses a global variable, not the local one defined later.

Use forward declarations, as suggested by @Egor:

local iseven, isodd

function iseven(n)
...
end

function isodd(n)
...
end

...
lhf
  • 70,581
  • 9
  • 108
  • 149
  • I don't get it. Is the problem that isodd doesn't exist yet at the point where iseven is executed, and the compiler therefore defaults to a global isodd that doesn't exist? So global functions can be later in the code but global ones can't? – JohnBig Feb 13 '22 at 14:54
2

Another way to get past this problem is to use tables. Plain local variables are probably more efficient, but with tables you dont need to manage the declarations.

local T = {}

local function evenOrOdd(n)
    return T.iseven(n) and "Even" or "Odd"
end

function T.iseven(n)
    -- code
end

The gist of this is that because the table is defined at the top, everything below it has access to it and you can dynamically change it's contents. When evenOrOdd is called, T.iseven should already be defined by then even though it was not defined when evenOrOdd was defined.

Rochet2
  • 1,146
  • 1
  • 8
  • 13
-1

Better check for num%2 - remainder of the division

FareakyGnome
  • 134
  • 4
  • 1
    It was just an example to show how my functions work. They are really too long to copy them here and the question can be answered anyway (see in the comments). – user6245072 Jul 21 '16 at 11:36