I am really astonished to hear protection keys being thought
of as "brittle" under transformation: that is just the opposite of what they are about!

Executive summary:

   - de Bruijn indices are a good assembly language of
       binding constructs, suitable for automatic transformation,
       but not suitable for human use

   - the classical name-based scheme is suitable for human
use, in principle, but is brittle under transformation (many transformations can not be applied without renaming); the more important these transformations
       become, the less suitable this scheme is, for either
       humans or machines (because of excessive renaming)

- Berkling's protection keys add flexibility to name-based schemes, *removing* their brittleness under transformation;
       it combines suitability for automated transformation
with readability for humans (in fact, both de Bruijn's and the classical name-based scheme are special cases of Berkling's)

The bigger issue is that scoping mechanisms in the de
Bruijn tradition are brittle for programming. They make
sense as intermediate representations or notations for
proof frameworks, because they can (sometimes) be
easier to reason about formally, but they're fragile in
the face of refactoring.

Sorry, but you have two directly conflicting statements
in one sentence there (unless I misunderstand what you
mean be "fragile"?): the point of de Bruijn choosing that
representation was to make automatic transformation
of scoped terms possible/easy, without breaking proofs.
That is the opposite of "fragile" to me.

To be fair, your suggestion is more moderate than de
Bruijn, although it's not clear whether you're proposing
the ability to refer to shadowed bindings of *all* variables
or just |this|.

Indeed, I wouldn't want to use de Bruijn indices at the
programmer level, while Berkling's protection keys enter
the frame only when naming alone isn't sufficient.

The problem is wider than 'this', 'this' just seems to be the main use case where the problem surfaces in Javascript practice at the moment. With scopes and prototypes, Javascript has two separate binding chains, but with prototypes, we can use different prefixes, "(prototype.)*.name", to skip entries in that chain.

Btw, have you ever wondered whether 'var'-bindings are
recursive?

function Outer() {
 var x = "outer", outer_x = x;
 function Inner() {
   var x = [x]; // var bindings are not recursive, are they?
   log(x + ' - ' + [outer_x]);
 }
 Inner();
}
Outer();

Will this log '["outer"] - ["outer"]', or '[[[[[[[[...', or something
else entirely?

I'm not making proposals yet, I'm just bringing some useful ideas to the attention of those who have to come up with proposals, hoping to make their work easier!-)

Seriously, the problem you're trying to solve is that |this|
is too fragile in the face of refactoring, but you're solving
it with a mechanism that's just as sensitive to refactoring.

It seems I am still not communicating Berkling's ideas
successfully (sorry about that):

his reduction systems were *based* on refactoring problem
descriptions (functional programs) to solution descriptions
(values of the functional language). His protection keys and
their handling were at the core of every scope-related
reduction/refactoring rule in those systems. If protection
keys were at all "brittle" in the face of refactoring, none of
his systems would ever have worked.

Quite contrary to being "brittle", protection keys introduce
the necessary flexibility that allows these systems to *avoid
breaking* the binding structure while automatically rewriting
the code.

It does make it syntactically simpler to fix than
|var self = this|, but the fix is just as brittle to the
next refactoring.

Perhaps it helps to clarify the problem: when we want to
transform a program in a way that introduces new bindings
where they get in between an existing binding and some of
its bound variables (shadowing them), we have to make
additional changes to compensate (to keep the original
binding structure and program meaning intact). If that is
what you mean by "brittle", there is just no way around it.

The only question is how to do the compensation. The
'var self = this' route is in the traditional line, renaming
bound variables. For non-'this' use cases, its main drawback
is that is changes the names chosen by the programmer.
If one does that during automated refactorings, the final
program is sometimes not recognizable to the programmer
who wrote the initial code (the alternative is for the
refactoring tool to balk and ask the programmer to resolve
the naming conflict before invoking the refactoring again).

For 'this', the issue is the other way round: the name is
not the programmer's choice, the binders for 'this' are
implicit (so we cannot rename at the binder), and one
cannot rename the variable without losing its special
functionality (so we end up with two names instead of
one: 'self' is lexically scoped, redirects to 'this', which
is more dynamically scoped).

The protection route is non-traditional, yes, but it neatly
solves the main issues: instead of renaming bound variables, it just protects variables from getting bound erroneously; instead of having to invent fresh variable names, automatic transformation tools just have to do a little arithmetic.

Claus

_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to