lua-users home
lua-l archive

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


On Tue, Aug 29, 2006 at 08:57:22AM +0200, Jose Luis Hidalgo Valiño wrote:
<snip>
> LUA_ENVIRONINDEX seems a way to hold data locally to a set of  
> functions ( or only one ) but without loosing the possibility of  
> access the full global environment (the thread environment) through  
> LUA_GLOBALSINDEX.

I like to think of LUA_ENVIRONINDEX as a sort of "lua_upvalueindex(0)": it is
like a shared upvalue among all C functions that have the same environment. If
by locally you mean private, then a closure is more appropriate, as Mildred
stated. Check toy example below.

> In lua 5.1 lua_setfenv "changes" the behavior of LUA_ENVIRONINDEX or  
> LUA_GLOBALSINDEX ? I'm not sure.

I don't understand what you mean, but since lua_setfenv changes the
environment of a function, thread or userdata, it affects LUA_ENVIRONINDEX for
C functions.

A simple example:

/* environ.c */
#include <lua.h>
#include <lauxlib.h>

static int environ_upv (lua_State *L) {
  lua_Number e, u;
  /* get environment data */
  lua_rawgeti(L, LUA_ENVIRONINDEX, 1);
  e = luaL_optnumber(L, -1, 0);
  /* update environment */
  lua_pushnumber(L, e+1);
  lua_rawseti(L, LUA_ENVIRONINDEX, 1);
  /* get closure data */
  u = luaL_optnumber(L, lua_upvalueindex(1), 0);
  /* update closure */
  lua_pushnumber(L, u+1);
  lua_replace(L, lua_upvalueindex(1));
  lua_pushnumber(L, e);
  lua_pushnumber(L, u);
  return 2;
}

int luaopen_environ (lua_State *L) {
  /* set current environment */
  lua_createtable(L, 1, 0); /* environ table */
  lua_pushnumber(L, 0);
  lua_rawseti(L, -2, 1); /* environ[1] = 0 */
  lua_replace(L, LUA_ENVIRONINDEX);
  /* push closures with default environment (above) */
  lua_pushnumber(L, 0);
  lua_pushcclosure(L, environ_upv, 1);
  lua_setfield(L, LUA_GLOBALSINDEX, "env1");
  lua_pushnumber(L, 0);
  lua_pushcclosure(L, environ_upv, 1);
  lua_setfield(L, LUA_GLOBALSINDEX, "env2");
  /* change environment using setfenv */
  lua_pushnumber(L, 0);
  lua_pushcclosure(L, environ_upv, 1);
  lua_createtable(L, 1, 0); /* new environ table */
  lua_pushnumber(L, 0);
  lua_rawseti(L, -2, 1); /* environ[1] = 0 */
  lua_setfenv(L, -2);
  lua_setfield(L, LUA_GLOBALSINDEX, "env3");
  return 0;
}

Lua 5.1  Copyright (C) 1994-2006 Lua.org, PUC-Rio
> require'environ'
> printupv = function(f) print(string.format('env: %d, upvalue: %d', f())) end
> printupv(env1)
env: 0, upvalue: 0
> printupv(env1)
env: 1, upvalue: 1
> printupv(env2)
env: 2, upvalue: 0
> printupv(env2)
env: 3, upvalue: 1
> printupv(env3)
env: 0, upvalue: 0
> printupv(env3)
env: 1, upvalue: 1
> printupv(env1)
env: 4, upvalue: 2
> printupv(env1)
env: 5, upvalue: 3
> printupv(env2)
env: 6, upvalue: 2
> printupv(env2)
env: 7, upvalue: 3

For more examples of LUA_ENVIRONINDEX, check liolib.c.

Cheers,
Luis.

-- 
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos 

-- 
Luis Carvalho
Applied Math PhD Student - Brown University
PGP Key: E820854A <carvalho@dam.brown.edu>