On Thu, 10 Sep 2009 01:00:36 -0400, David Manura <dm.lua@math2.org> wrote:
The documentation for struct.declare defines these code fields:
1. open={m1, ...}
2. pre="..."
3. files=f1 or files={f1, ...}
4. post="..."
5. environment="..."
When first seeing the examples, it was not obvious to me when fields
#2-5 were appropriate and how they interacted. As I see, each of
these represents code and they are executed in sequence. They differ,
perhaps arbitrarily, in that #3 accepts file names, but the others
accept code strings (though you could specify file names in the others
via a dofile or require, as some examples do), and only #5 handles a
return value. Lacking #3, you can arbitrarily choose to place your
code inside #2, #4, or #5. Would something like the following make
the model simpler and more general?
structure.declare {
name="test";
open={"_G", "os"};
environment = [[
pre.....
dofile '.....' .....
post....
return t -- optional (return may be omitted)
]]
}
or using e.g.
environment = {[[pre.....]], '@pre2.lua', '@file1.lua',
[[post....; return t]]}
The typical purpose of #2-4 seems to be to define a module that wraps
another module, whereas the name/signature/location fields define how
that wrapped module is bound into the local namespace tree.
Yes, the name/signature/location fields do define how the structure is used, and there can be several such fields in one structure definition, allowing the same code to be used in multiple ways.
Your suggestion that 'environment' alone suffices is accurate. I considered two usage models explicitly, although, looking back, it appears that I wrote almost entirely about just one: wrapping an existing module with a structure declaration. The other usage model is simply writing code (or re-using code) where, at some point in its development, a decision is made to make it a module.
In the latter case, structure declarations will ideally contain only 'open' and 'files' clauses (out of the 5 clauses that process code). When this pattern is followed, there are two small benefits: (1) the file names are declared, so they can be extracted programatically when analyzing the modules in a particular system; and (2) a search path for code loaded by Darwin can be distinct from the path(s) used by the native Lua module system. Darwin supports a customizable search path for file names listed in the 'files' clause.
When loading files of code, especially those written by other people, the 'pre' and 'post' clauses let you wrap those files with additional code without having to edit the file -- this is merely a convenience, of course.
In my opinion, this makes a very good usage pattern:
Use 'open' to declare dependencies on other modules and 'files' to load code. When you do not want to (or cannot) edit the files, use 'pre' and 'post' to wrap the files with your own customizations.
However, I wanted to facilitate the re-use of existing modules, and that requires the "full expressiveness" of the 'environment' clause. As you have observed, you can do everything with the 'environment' clause and, therefore, 'files', 'pre', and 'post' are unnecessary. The 'files' clause (with 'pre' and 'post' as needed) represents a usage pattern that I would like to encourage. Of course, one has no control over how one's inventions are used. :-)
Jim