On Jan 26, 2012, at 4:57 PM, Brendan Eich wrote:
> Allen Wirfs-Brock wrote:
>> On Jan 26, 2012, at 11:51 AM, Brendan Eich wrote:
>>> We could say event handler attributes are scoped by the most-nested scope
>>> -- the scope due to the last <script> element that was closed before the
>>> element with the event handler attribute was processed.
>>> This means generated scripts (document.write or DOM create* calls) do not
>>> see the generating script's let and const bindings.
>>
>> Why closed? All declarations within a /Program/ are instantiated before
>> evaluating any code in its <script> element so generated scripts should be
>> able to reference the bindings for those declarations. However, if such
>> reference are actually evaluated they might fall into the bindings' temporal
>> dead zones.
>
> You're right, the entire outer <script> has been parsed and declarations
> processed before anything runs. And the script element is appended to the DOM
> too. It all works, except of course you can't tell what's potentially
> shadowing anything!
Yes, this makes references to let and const bindings inherently unpredictable.
But also var and function bindings as they can be shadowed by let/const. STL
would at least give you an error that hopefully will show up in an error
console.
> ...
My point was that we shouldn't try too hard to fix problems that aren't under
our control. We need to be aware of them and should try to make things any
worse. But trying to fix async load issues in our spec. seems like address
the problem at the wrong level.
>
>> <script src="someLib.js" type="application/javascript" async="async"
>> id="lib1"></script>
>> <script src="anotherLib.js" type="application/javascript"
>> async="async"id="lib2"></script>
>> <script src="baseApp.js" type="application/javascript" async="async"
>> id="base" after="lib1"></script>
>> <script src="extraApp" type="application/javascript" async="async"
>> after="lib2,base"></script>
>
> Because that's brittle and slow -- you don't care about order, you typically
> just want to race and exploit as much parallelism as possible, given host
> CPU(s), the intervening network, TCP connection sharing/limits/etc.
But the ordering dependencies are real. If you don't explicitly identify them
and they also aren't implicitly recognized then your application will be
unreliable.
>
>>> The situation is messy enough that I question the win of nesting scopes.
>>> True, a global object subject to async-loaded effects is no picnic, but it
>>> is the devil we know. And these var and function bindings, however racy,
>>> are not supposed to be lexical, as let and const are.
>>
>> I think these are the alternatives we currently have under consideration:
>>
>> SQ (status quo): every top level declaration are all implemented as
>> properties of the global object
>> STL (Single Top Level): All script blocks share a declarative environment
>> for new (not var and function) kinds of declarations that shadows the global
>> object. Scripts with duplicate declarations are rejected.
>> TLpSi (Top Level per script, isolated): Each script block has a declarative
>> environment for new (not var and function) kinds of declarations. Each
>> shadows the global object but are invisible to each other.
>> TLpSn (Top Level per script, nested): Each script block has a declarative
>> environment for new (not var and function) kinds of declarations. Each is
>> logically nest within and shadows the previously processed script
>>
>> STL is what I'm proposing.
>
> I'm pretty sure the collisions-are-rejected thing is going to burn. It's the
> opposite of what people not only abuse (unknown latent bugs), but absolutely
> use and rely on today, with var and function among scripts.
With STL we would be saying that if you need redefinition/multiple definition
behavior you need to continue to use var and function or you need to refractor
to use modules/export/input. But you can'tuse naked let/const. Some people
would get burned by this and conclude that var is always preferable to let.
But others would learn about modules. In either case, we would have a
consistent semantics for let/const. BTW, we should make sure that modules can
actually support the use cases that need such multi/redefinitions. I think it
is mostly various ways of doing polyfill like things.
>
>> I think that TLpSn corresponds to Andreas preference. One way to look at
>> TLpSn is that uses shadowing to accept the duplicate declarations that STL
>> rejects. This seems like a problem that is better addressed by using
>> modules. TLpBn
>
> (s/B/S/ right?)
yes
>
>> also raises issues like, what scope does an indirect eval use? I haven't
>> head anyone recently advocating for TLpSi. You can achieve almost the same
>> thing using SQ by wrapping a block around each script body.
>
> Right, although TLpSi is still attractive as a parallel to function bodies,
> where we agreed body-level let has to bind in a body block that shadows
> parameters and vars. Not much of a plus but it's a plausible alternative.
did you just say that this is legal:
function f() {
var b;
let b;
}
and interpreted as:
function f() {
var b;
{ let b; }
}
That wasn't by understanding of the take aways from the Nov. meeting.
I kind of like TLPSi, but I think it would be counterintuitive for web
developers who write in-line scripts such as:
<script>
const debug = true;
</script>
<-- a bunch of html -->
<script>
if (debug) {...}
</script>
If we only had src based scripts it might be the right thing...
>
>> In general, when I start think about the ways that lexical declarations in
>> separate scripts might interact I run into issue that are probably best
>> resolved using modules. I'm inclined to favor the simpler solution and leave
>> it to modules to deal with managing actual interdependencies cases.
>
> Is STL the simplest solution for users?
It avoids issues like:
<script>
const debug = true;
function f1 () {
if (debug) log(...);
...
}
</script>
<script>
const debug = false;
function f2 () {
if (debug) log(...);
f1(); // but this logs regardless
...
}
</script>
<script>
let debug=false; //this has no effect
f1();
f2();
</script>
the behavior of this under TLpSn is perfectly normal given lexical scoping.
However, there is no physical nesting so it is likely to be surprising to many
users.
Allen
>
> /be
>
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss