return when desugaring to closures

David-Sarah Hopwood david.hopwood at
Thu Aug 21 18:45:32 PDT 2008

Brendan Eich wrote:
> On Aug 21, 2008, at 4:05 PM, David-Sarah Hopwood wrote:
>> Brendan Eich wrote:
>>> The maddening mix of dynamic scope (the hopeless global top-level,
>>> with, eval) and lexical scope [...]
>> 'with' is lexically scoped.
>> <> 
> There, you wrote
> "The first example illustrates (but does not prove) that 'with' actually
> provides lexical scoping, *provided* that all free identifiers in the
> scope of the 'with' exist as properties of the supplied scope object. "
> The *provided* is not guaranteed by 'with', so if it's not satisfied, 
> then by your own argument 'with' does not provide lexical scoping.

My statement in that post was imprecise: 'with' *always* provides
lexical scoping for all of the identifiers that it affects. It does not
affect the scoping of identifiers that do not exist as properties of the
scope object: those have the same scoping as they would have had without
the 'with'.

Of course if that set of properties changes, then the effect on the scope
is "dynamic" in some sense, but that's still not "dynamic scoping".

I made the "*provided*" caveat just because at that point I hadn't done
sufficient testing and careful analysis of the spec to confirm that 'with'
actually is always lexically scoped. But the design of Jacaranda (the
object-capability subset I'm working on) depends on that, so I certainly
hope it's correct.

In your example below, the opt_* variables are globally scoped in the
case where they are not affected by the 'with'. The global scoping is
not fully lexical (and I fully agree with your dismissal of the global
scope semantics as "hopeless"), but it isn't the 'with' construct that
is causing that.

> Perhaps you meant to write "'with' may but not must be lexically scoped"?
> Consider this counter-example:
> var opt_A = false, opt_B = 0, opt_C = ""; // defaults
> function setOptions(opts) {
>   with (opts) {
>     if (opt_A) setOptionA(true);
>     if (opt_B) setOptionB(opt_B);
>     if (opt_C) setOptionC(opt_C);
>   }
> }
> setOptions({opt_A: true, opt_C: "hi"});
> setOptions({opt_B: 42, opt_C: "bye"});

This is lexical scoping with conditional shadowing. If it were dynamic, then
you'd expect:

   function setOptionB(x) {
     print(x == opt_B);

   setOptions({opt_B: 42});

to print true, but it actually prints false.

> I'm not recommending this kind of code, but IIRC Lars Hansen pointed out 
> the pattern, based on sightings in the wild.
> Is this "dynamic scope" in the classical sense? No, but it smells as bad 
> and has similar undesirable properties ;-).

Oh, I'm certainly not disputing the latter. My discussion of 'with' is made
in the spirit of "know your enemy".

David-Sarah Hopwood

More information about the Es-discuss mailing list