lua-users home
lua-l archive

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


D Burgess wrote:
 ...  functions to instantiate "environment-less"
functions which bind dynamically when called.

This would do the trick for me.

I thought i might as well post this message to the lua mailing list, previously i personally emailed this to Mr Burgess to get his feedback, it seems as though it does what he is after. I now unleash this to public forum for comments.

...

I was following the thread on the lua list as the ability for a function to use the threads global environment rather than the environment inherited during the closure creation has great appeal to me. I myself wanted to be able to alter functions to use the globals of the thread in which they are invoked as opposed to having the hassles of managing multiple closures for multiple lua threads.

I have attached a patch which i think does what you want, it certain does what i want to do.

This is the code that i used to do my testing, at present the only function that will take dynamically binded global values from the thread is the "count" function. To the clearing of the closure environment i added a clearenv function and put the necessary support into the lua core.

Andrew

*testing.lua*

count = function(start, name)
  j = start
  for i = 1, 4 do
    print("in thread " .. name .. ", j = " .. j)
    j = j + 1
    coroutine.yield()
  end
  print("thread " .. name .. " is done!")
end

newthread = function(start, name)
  local th = coroutine.create(function()
    -- replace the threads environment with a simple environment
    local t = { print = print, tostring = tostring, coroutine = coroutine }
    setfenv(0, t)
    -- the the actual thread operation
    print("thread " .. name .. " starting...");
    count(start, name)
    print("thread " .. name .. " is finished!");
  end);
  return th
end

-- clear count environment, we want it to use the threads global env
clearfenv(count)

-- prepare two threads to run function count.
t1 = newthread(1, "t1")
t2 = newthread(10, "t2")

-- set the master global value to something that we can check to make sure it doesn't change
j = 123

-- execute the coroutines
coroutine.resume(t1)
coroutine.resume(t1)
coroutine.resume(t1)
coroutine.resume(t2)
coroutine.resume(t1)
coroutine.resume(t2)
coroutine.resume(t1)
coroutine.resume(t2)
coroutine.resume(t2)
coroutine.resume(t2)

-- ensure the master j value has not changed
print("j = " .. j);

*output.txt*

thread t1 starting...
in thread t1, j = 1
in thread t1, j = 2
in thread t1, j = 3
thread t2 starting...
in thread t2, j = 10
in thread t1, j = 4
in thread t2, j = 11
thread t1 is done!
thread t1 is finished!
in thread t2, j = 12
in thread t2, j = 13
thread t2 is done!
thread t2 is finished!
j = 123


diff -r lua-5.1.1/src/lapi.c lua-5.1.1.patched/src/lapi.c
758a759,778
> LUA_API int lua_clearfenv (lua_State *L, int idx) {
>   StkId o;
>   int res = 1;
>   lua_lock(L);
>   api_checknelems(L, 1);
>   o = index2adr(L, idx);
>   api_checkvalidindex(L, o);
>   switch (ttype(o)) {
>     case LUA_TFUNCTION:
>       clvalue(o)->c.env = NULL;
>       break;
>     default:
>       res = 0;
>       break;
>   }
>   lua_unlock(L);
>   return res;
> }
> 
> 
diff -r lua-5.1.1/src/lbaselib.c lua-5.1.1.patched/src/lbaselib.c
160a161,169
> static int luaB_clearfenv (lua_State *L) {
>   getfunc(L);
>   if (lua_iscfunction(L, -1) || lua_clearfenv(L, -1) == 0)
>     luaL_error(L,
> 	  LUA_QL("clearfenv") " cannot change environment of given object");
>   return 1;
> }
> 
> 
446a456
>   {"clearfenv", luaB_clearfenv},
diff -r lua-5.1.1/src/lgc.c lua-5.1.1.patched/src/lgc.c
225c225,226
<   markobject(g, cl->c.env);
---
>   if (cl->c.env)
>     markobject(g, cl->c.env);
diff -r lua-5.1.1/src/lua.h lua-5.1.1.patched/src/lua.h
195a196
> LUA_API int   (lua_clearfenv) (lua_State *L, int idx);
diff -r lua-5.1.1/src/lvm.c lua-5.1.1.patched/src/lvm.c
433c433
<         Protect(luaV_gettable(L, &g, rb, ra));
---
>         Protect(luaV_gettable(L, cl->env ? &g : gt(L), rb, ra));
444c444
<         Protect(luaV_settable(L, &g, KBx(i), ra));
---
>         Protect(luaV_settable(L, cl->env ? &g : gt(L), KBx(i), ra));