[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: In praise of globals
- From: Jay Carlson <nop@...>
- Date: Wed, 17 Apr 2013 23:23:06 -0400
On Apr 15, 2013, at 6:18 AM, Matthew Wild wrote:
> People can and will [monkey-patch] anyway. It often breaks things - for example
> reloading plugins must clean up after themselves,
Reloading *modules* is broken in a world where everybody has squirreled away
local ipairs=ipairs
local module1=require("module1")
local xpairs=module1.xpairs
function give_me_referential_integrity_or_give_me_death()
assert(module1.xpairs == xpairs)
end
The canonical way to be reload-friendly is for the module1 code to get any existing module1 table and mutate it. But that doesn't help with the "local xpairs" problem.
This is fixable outside core. Instead of the above pattern, write:
local ipairs, module1, xpairs
on_any_module_reload(function()
ipairs=_ENV.ipairs;
module1=_ENV.require("module1");
xpairs=module1.xpairs
end)
and trigger it off a monkey-patched require...but that's so ugly we're going to do one of the following:
• Something really gross with debug.*
• Run all of our code through m4.
• Pull a java and say, "Source code isn't for humans, it's a serialization form for IDEs."
Having just spent a good day or so writing/debugging gcc __asm__ blocks inside #defines I do have some sympathy for Gosling's point about the C preprocessor throwing our source code into an unstructured pile-of-ASCII jail. There's really no way of reasoning locally about any bit of C source, which is the non-marketing reason Java doesn't have #define.
Anyway, I think there's some kind of interaction with initialization hoisting too, since although we don't really want #define, we don't really want variables either; we want "equate".
static ipairs;
import module1; -- sugar for static module1 = require("module1")
static module1.xpairs;
...which create new bindings as "local ipairs,module1,xpairs" would. The reason I use "static" is I want something like this to work:
for l in io:lines() do
static validSsn = regexp.pattern("&?@#some horrible thing")
if validSsn(l) then print(l) end
end
where the semantics are
local _$local1 = regexp.pattern("&?@#some horrible thing")
for l in io:lines() do
local validSsn = _$local1; [...]
An alternative might be to cache per call-point, but in the case of little languages, you really want the regexp compiler to run at chunk load time so it can point out your syntax errors.
Why am I bringing this up in the context of reloading? Because it seems like the static initializers are the stuff you definitely want to rerun on reload.
local _local$1, _local$2, [...]
local _$local1
local function _$local1_init()
_$local1 = regexp.pattern("&?@#some horrible thing") end
end
_$local1_init()
for l in io:lines() do ... end
[...]
and have some mechanism to call all the _$local_init functions.
Jay