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

Reply via email to