lua-users home
lua-l archive

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

I don't think an implementation that just returns nil by default is what we want.  Certainly this provides a standard interface (which I agree would be entirely beneficial), but so does a simple document listing function prototypes.  I think rather than add empty weight to the API, the team should release a set of documents describing how libraries should be written and defining a set of common interfaces to such system dependent functions as setenv or putenv.  Maybe I am too much of a purist, but I think this is the absolute most that should be done to Lua, since it accomplishes our goals but doesn't modify the API.

Also, the standard interface should be absolutely as thin as possible.  Rather than providing a table as an abstraction of getenv and setenv (as Rici proposes), the standard interface should define a one-to-one mapping from Lua functions to C functions such as getenv, setenv, putenv, and ChangeEnvironmentVariableToString (or whatever C functions implement the desired task).  If a function isn't provided by the current OS, then the function is left undefined in the environment.  This provides optimal performance and maintains portability:

local function resolve_setenv ()
    if std.setenv then
        return std.setenv;
    elseif std.putenv then
        return std.putenv;
    elsif std.ChangeEnvironmentVariableToString
        return std.ChangeEnvironmentVariableToString;
        error ("std.setenv/putenv/ChangeEnvironmentVariableToString is not implemented in this environment");

my.setenv = resolve_setenv ();
my.setenv ("KEY", "VALUE");

Using a one-to-one map such as this, the user can define whatever high-level abstractions she wants.  Also, this approach doesn't bring the interface down to the "lowest common denominator" when different platforms provide more or less functionality.  For example, if some OS provides ChangeEnvironmentVariableToNumber in addition to ...ToString, this functionality is not lost in the standard.  This implementation is entirely blind to what OS it is running under; it cares only which functions are defined in the current environment.

Writing a standard library that morphs based on the OS is extremely hard or impossible to write.  The only common denominator is C 89, which Lua already implements decently.  A one-to-one mapping is the only way to safely provide system dependent functionality to all platforms.  Anything else will only be portable to a finite set of OS, which is not acceptable.

On Sun, 2006-01-08 at 12:12 -0500, Rici Lake wrote:
On 8-Jan-06, at 11:00 AM, Chris Marrin wrote:

> This is all good discussion. But let me say that my original intent 
> was to say that there are many capabilities that Lua has built in 
> (file I/O, a few os functions). But this set is incomplete and 
> therefore other libraries need to be brought in.

Leaving aside loadlib, the facilities Lua offers are essentially those 
guaranteed in standard C (89). So it's not an arbitrary choice, really.

However, I strongly agree with this:

> The choice of libraries is many and often conflicting and I think this 
> hurts Lua development.

Lua should not, in my opinion, include as standard libraries which 
require OS interfaces which may not exist on a conforming C 
implementation [Note 1]. However, there are many OS interfaces which 
are commonly available on popular platforms, and it would be nice if 
the Lua API for such interfaces were consistent. (For example, the name 
of the Lua function os.setenv should not depend on whether the 
underlying platform uses setenv, putenv, or 

So I (continue to) believe that an important step is to define (and 
achieve consensus on) the library APIs which should be used to bind 
such OS features. That way, we could at least know that if there were a 
way of setting environment variables, it would be called in the same 
way, say os.setenv(varname, value) where both varname and value are 
strings [Note 2]; and furthermore that os.setenv should not do 
something else. (In fact, in this particular case, it could be included 
in the standard distribution with a default implementation which 
returned nil; a particular os library could then replace that with an 
implementation that did change the environment variable and returned a 
true value.)

The case of loadlib() provides an example of how this model can work: 
it is an OS-specific facility, but the interface is well-defined in the 
language, and the default implementation simply returns an error 

There is always the temptation to create shallow wrappers around 
OS-dependent facilities, which mimic the low-level OS API. This is 
usually a mistake; it makes it harder to write cross-platform code, and 
it often results in APIs which are "un-Lua-like". As a case in point, a 
directory iterator is much more consistent with Lua style than would be 
a shallow wrapper around opendir(), readdir(), etc.


Note 1: In fact, it is possible that Lua already includes too much in 
the standard distribution. For example, embedding Lua often requires 
replacing I/O implementations.

It often comes as a surprise to embedders that print() and io.write() 
are unrelated, and that loadfile() cannot accept a file object returned 
by It would be worth thinking about how to make it possible 
to synchronize the implementations of I/O between the base library and 
the io library, so that, for example, when the io library is included, 
base library implementations are redefined to use it.

Note 2: Personally, I'm not convinced by the function call interface to 
getenv and setenv; it seems to me that it would be more natural to 
implement this directly as a table-like object which implements __index 
(by default) and __newindex (if that facility is available). This would 
allow the possibility of simulating setenv with an ordinary Lua table, 
in the case that the underlying platform does not provide any setenv