The idea is simply that (lexically scoped) variables usually
are bound to the next enclosing binding of the same name,
while protected (lexically scoped) variables are bound to
the next _outer_ enclosing binding of the same name
(each protection key skips one level of binding, lexically).
To clarify, if I have the code
foo(#x)
and suddenly I realize that I need a to guard it with a condition,
if (bar) {
foo(#x)
}
this would ?not? change the binding of #x since, although I have
introduced a new let scoped block, x is not declared in that scope so
it is not counted against the stack of #'s.
This would _not_ change the binding of #x, because it
does not introduce or remove any bindings for x. Both
bindings and protections are specific to variable names.
It is not always easy to count scopes though without knowing
a lot of details. E.g. changing
function f() {}
(function () {
function () {
return f;
}
})()
requires two hashes
function f() {}
(function () {
function f() {
return ##f;
}
})()
since f was introduced both into the body scope, and into
the outer scope via the function declaration.
The counting is (usually) just by enclosing binders, not by how
many constructs or nested scopes they affect. So, I would count
one intervening binding here, and one protection # to keep the
binding structure as before:
function f() {} // target this binding
(function () {
function f() { // skip this binding
return #f;
}
})()
We could have this instead, where there'd be two bindings
for f to skip, and two protections to keep the binding structure
intact:
function f() {} // target this binding
(function () {
var f = function f() { // skip these bindings
return ##f;
}
})()
It seems brittle,
Not usually (did your counting scopes cloud the idea, or
am I missing some Javascript-specific problem?) - it has
been the basis of soft- and hardware implementations
of functional (and functional-logic) languages.
If we can find the binding for an unprotected variable, we
can find the binding to skip for a protected variable; one
binding and one protection cancel each other; once an
unprotected variable has a binding, it is bound.
It is still just the usual lexical scoping in action - the only
change is that shadowed bindings can now be reached,
by protecting variables from shadowing bindings.
That is all one needs to know about the system at the
programmer-level, at least for a language like Javascript,
whose operational semantics isn't defined by rewrite
rules (*).
Hope this helps,
Claus
(*) As a student, I found programming with it very intuitive,
even though the language we were given did execute by
rewriting (so the protection keys adjusted to dynamically
changing program structure, e.g, when a function definition
was inlined at a call site);
implementers find it similar to deBruijn-Indices (if an
implementation renames all variables to be the same,
the resulting protection keys correspond directly to
indices for stack access), but those are not usually
palatable to programmers;
http://en.wikipedia.org/wiki/De_Bruijn_index
when reasoning about programs, or rewriting programs,
it means that names are less of a problem, because we
can always preserve the binding structure (no more
exceptions like "you can wrap code in a function,
provided the code does not mention the function
name or parameters").
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss