lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Thu, 6 Sep 2007, Jeff Wise wrote:

  print("Call # 2 --------------------------------")
  assert(loadfile("C:\\lua\\source\\dummy2.lua"))

loadfile just creates a function; the above never calls it.
(Calls 1 and 3 are fine.)

Thank you for your reply.  Unfortunately, I have no clue what you are
telling me.  My background is probably very different than most on this
forum, as it is mostly IBM mainframe assembler.  Perhaps this is the source
of my difficulty.  I apologize for my lack of comprehension.

[[[ snip ]]]

It may be that the "arg[1]" construct is ONLY valid from "command line
arguments".  If that is the case, I'm sure lua provides some other mechanism
for chaining program execution.  The old mainframe makes no distinction in
its linkage conventions.

There are actually several things going on here, some related to the Lua
language and some related to the compiler. The arg array is constructed
by the lua compiler for the convenience of the loaded program and is not
*really* a language construct.

Fundamentally, Lua is a stack-oriented language. Functions accept
parameters from a stack and return results to the stack. When you
declare a function, the compiler allows you to assign names to the
parameters pushed onto the stack. When you declare a function, say

  function Booger( Arg1, Arg2 )
    io.write( Arg1, Arg2 )
  end

you are creating a global variable named Booger that holds a function.
That function expects two arguments on the stack. They are given the
names Arg1 and Arg2.

This function declaration syntax is synonymous to this:

  Booger = function( Arg1, Arg2 )
    io.write( Arg1, Arg2 )
  end

which *also* creates a global variable named Booger that holds a
function accepting two parameters from the stack, the first named Arg1
and the second named Arg2.

Since parameteres are passed on the stack, there can be any number of
them. You can declare a function that accepts a variable number of
parameters like this:

  Booger = function( ... )
  end

This creates a variable named Booger that contains a function that
accepts a variable number of parameters on the stack.

Since the variable parameters don't have names, how can Booger get to
them? One way is like this:

  Booger = function( ... )
    local Args
    Args = { ... }
    for index, value in pairs( Args ) do
      io.write( "Index: ", Index, " Value: ", Value, "\n" )
    end
  end

The construct { ... } creates a table holding the parameters that were
pushed onto the stack, but not assigned names. Args = { ... } stores
that table in a variable where you can get at it.

When you use something like:

  loadfile( "booger.lua" )

you create a function containing the result of compiling "booger.lua".
You can store this to a variable, like this:

  Booger = loadfile( "booger.lua" )

Since Booger now contains a function, it can be called just like any
other function:

  Booger( Arg1, Arg2 )

A statement like:

  assert( loadfile( "booger.lua" ) )( Arg1, Arg2 )

combines several things into one statement, hiding what's going on.
It's essentially equivalent to:

  Booger = assert( loadfile( "booger.lua" ) )
  Booger( Arg1, Arg2 )

except that Booger is a temporary variable that you throw away
after the call.

Now, compiling a Lua file results in a function that you can call, but a
Lua file does not have a function declaration, so you can't declare the
parameters to it. Essentially, a Lua source file *implicitly* contains a
function that accepts a variable number of parameters. This means that
our load above is equivalent to:

  Booger = function( ... )
    contents of "booger.lua" here
  end

That is, it creates a variable containing a function that accepts a
variable number of parameters, none of which have names.

Since the code within booger.lua is a function that accepts a variable
number of parameters, it can access its parameters using the { ... }
construct, which constructs a table from all of the unnamed parameters
that were pushed. In other words, if I take this example from above:

  Booger = function( ... )
    local Args
    Args = { ... }
    for Index, Value in paris( Args ) do
      io.write( "Index: ", Index, " Value: ", Value, "\n" )
    end
  end

and snip out the insides, I can create a "booger.lua" containing:

  Args = { ... }
  for Index, Value in paris( Args ) do
    io.write( "Index: ", Index, " Value: ", Value, "\n" )
  end

and get the same behavior if I do:

  Booger = assert( loadfile( "booger.lua" ) )

When the lua compiler loads a program, it creates the arg array from the
command line parameters *in addition* to pushing the extra parameters on the stack. However, this is primarily as a convenience to the lua
program. The arg array is *not* created for a normal function, so it is
*not* created for a function compiled by loadfile.

However, since the parameters are *also* pushed on the stack, it is
possible for the booger.lua above to be executed from the command line
and accept its arguments from the command line.

Some things that go into the arg array are *not* present in the
arguments passed on the stack; basically, anything before arg[ 1 ] is
unavailable, so you can't get at arg[ 0 ] and arg[ -1 ] in a table
constructed from the variable number of parameters on the stack.

Hope this helps!
--
roger ivie
rivie@ridgenet.net