[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Deprecating setfenv()
- From: David Kolf <kolf@...>
- Date: Tue, 12 Jan 2010 10:13:14 +0100
Miles Bader schrieb:
> "loadin" (etc; I assume they'll provide analogues for other load
> variants) combines the operations of parsing and environment-setting;
> that suffices to replace _some_ current uses of load+setfenv, but people
> actually make use of the Lua's current ability to execute those
> operations separately -- e.g., to re-evaluate the same loaded contents
> in different environments without the overhead/uncertainty [e.g. .. file
> goes away!] of re-loading/parsing. loadin (etc) do not replace the
> latter usage.
I would like to second this and add an example. I am writing an
experimental MUD server which would have several domains of "untrusted"
code, where each domain has its own environment.
They would still share a lot of code and as a replacement for dofile ()
I wrote the following code:
objects.includememory = objects.includememory or
setmetatable ({}, {__mode = "v"})
function objects.include (file, env)
local env = env or getfenv (2)
local buf = objects.includememory[file]
if not buf then
local code, err = objects.safereadfile (file)
if not code then error (err, 2) end
if code:byte () == 27 then
error ("attempt to load a binary chunk", 2)
end
buf, err = loadstring (code, "@"..file)
if not buf then error (err, 2) end
objects.includememory[file] = buf
end
setfenv (buf, env)
return buf ()
end
[objects.safereadfile () is just a function that makes sure the filename
is nice and returns the file contents.]
This function would reuse the loaded code as long as it is still in
memory for different environments. For this I would need setfenv or an
equivalent feature.
It also uses by default the environment of the caller using getfenv (2).
Without getfenv or something equivalent this wouldn't be possible. When
calling it, you would always need to specify an environment. (So each
environment would need something like a _G variable to pass to the
include function).
The above code can be implemented using loadin and I already did so, but
it isn't as efficient as it can't reuse the compiled code for different
environments and could only reuse the loaded code.
Here is what it would look like:
objects.includecodememory = objects.includecodememory or
setmetatable ({}, {__mode = "v"})
function objects.include (file, env)
env.includememory = env.includememory or
setmetatable ({}, {__mode = "v"})
local buf = env.includememory[file]
if buf then return buf () end
local s = objects.includecodememory[file]
local err
if not s then
s, err = safereadfile (file)
if not s then error (err, 2) end
objects.includecodememory[file] = s
end
local f, err = loadin (env, s, "@"..file, "t")
if not f then error (err, 2) end
env.includememory[file] = f
return f ()
end
Best regards,
David