Recursion

The BASIC interpreter scans the program line by line, starting necessarily with the main program. When it meets a procedure or function name for the first time it starts to look for a program line beginning with DEF followed by its name. If it cannot find it, it raises an error. If it does find it, it links the name and position of the definition into a linked list, for a faster lookup next time. This means that recursive and mutually recursive definitions work without any difficulty.

The Lua interpreter does none of this scanning. So that a variable just has the value nil until it has been assigned a non-nil value. When the interpreter meets a declaration of a local variable it assigns to the variable's name the number of the next free slot on the current chunk's stack. Henceforth only the stack slot is used for referring to the variable's value.

This definition does not work:

  local f = \ (a, n)
            if n <= 0 then => a end
            => f (n * a, n - 1 )
            end
because f's scope only begins after the statement declaring it local. Instead you must write

  local f
  f = \ (a, n)
        if n <= 0 then => a end
        => f (n * a, n - 1 )
        end
A similar discipline must be observed for mutually recursive functions.

  local f, g
  f = \ ..... g .... end
  g = \ ..... f .... end
The first time the interpreter meets g its value is nil, but f will not care about this until it is called as a function. By the time either f or g is called each will have its correct value. This is rather like the forward declarations that have to be made in C to implement mutually recursive definitions.

Tables can be used as objects.

     local P = { x = 120, y = 300 }
     P.move = \ (self, a, b)
                   self.x + = a
                   self.y + = b
               end -- function
    P:move (10, -50)
    print (P.x, P.y)  --> 130  250
We have seen that P.move is just sugar for P [ "move" ]. The colon notation makes

 P:move ( a, b) 
an abbreviation for

 P.move ( P, a, b) 
Note that there is no independent function P:move. Despite this some people refer to P:move as a method for the object P.

We could also have written the code above as

     local P = { }
     do local _ENV = P
       x, y = 120, 300
       move = \ (self, a, b)
                   self.x + = a
                   self.y + = b
               end -- function
       show = \ (self) print (self.x, self.y) end -- function
     end -- do
     P:move (10, -50)
     P:show ( )  --> 130  250
It comes down to personal preferences in style.

The point of the colon notation is that it puts the table itself within the scopes of function values of the table. I never really got object-oriented programming until I understood how Lua lets you use tables this way.