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

Mike Samuel mikesamuel at gmail.com
Sat Mar 26 16:58:31 PDT 2011


2011/3/26 Mike Samuel <mikesamuel at gmail.com>:
> 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?


I think I was wrong about a function declaration introducing two bindings.

I thought the function f() {} behaved the same as the var f = function
f() { ... } below.

var f = function f() { alert(typeof f); };
alert(typeof f);  // alerts function
var g = f;
f = 3;
alert(typeof f);  // alerts number
// alerts function because the reference to f does not bind to the global f
g();



>>    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