Inner functions and outer 'this' (Re: That hash symbol)

Mike Samuel mikesamuel at gmail.com
Sat Mar 26 16:53:24 PDT 2011


2011/3/26 Claus Reinke <claus.reinke at talk21.com>:
>>> 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

The line directly above introduces two bindings in two scopes.  Did
you mean that both of them are skipped, or just one?

>    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

I have never used such a feature, and thanks for recounting your
experiences below.  Counting scopes seems brittle to me because
changes to intervening scopes can break code that is distant from
them.  That's, of course, always the case with introducing a variable
that may mask.

> 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").
>
>


More information about the es-discuss mailing list