Module isolation
On Jan 10, 2010, at 9:30 PM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
On Jan 10, 2010, at 1:14 AM, Kevin Curtis wrote:
From SecureEcmaScript proposal: 6. The top level binding of this in an evaled Program is not the global object, but rather a frozen root object containing just the globals defined in the ES5 spec.
For many current applications, the frozen |this| object is not
necessary or desirable in global code. The essential characteristic of modules, isolation for each module's "inside" from unimported effects of other modules, does not necessarily mean no mutation of primordial objects.On the contrary, it does necessarily mean that. If you can mutate primordial objects, then there is no isolation of any module. There may be a reduction in the possibilities for accidental interference between modules, but that should be distinguished from isolation.
Who said primordial objects are shared between modules? You assume too
much in assuming your favored conclusion.
There are three things a module has to deal with to interact with JS
in browsers:
- The global object and its Object, Date, etc. primordials.
- The |this| binding for "global" code in the module, at the module's
top level. - The scope chain tail object, the only object on the scope chain for
global code in ES1-5.
These are not necessarily the same at all. The lexical_scope proposal
eliminates 3 by making the top-level a lexical environment, not an
object. The |this| binding may or may not refer to the global object.
And it's not settled whether, in browsers with many global objects
(one per window/frame/iframe) there is only one global among N>1
modules, or a global per module.
If modules do not use free variables, only what they import, then
you're wrong that isolation requires freezing. Modules could use their
own primordials, or none (only library code, possibly better versions
of Date, etc.). The object and array initialisers and regexp literals
would have to construct using some "original value" of Object, Array,
RegExp. But not necessarily a frozen one, if per-module.
That you conflate frozen primordials with isolation is exactly the
kind of over-specification through shortest-path evolution of ES5 to
which I object. It is not going to fly in TC39 among all the browser
vendors. We need to hear from Apple, Microsoft, and Opera, but I'm
already objecting to this kind of axiom planting. Let's back up and
talk about modules from premises forward.
On Jan 10, 2010, at 9:38 PM, Brendan Eich wrote:
That you conflate frozen primordials with isolation is exactly the
kind of over-specification through shortest-path evolution of ES5 to
which I object. It is not going to fly in TC39 among all the browser
vendors. We need to hear from Apple, Microsoft, and Opera, but I'm
already objecting to this kind of axiom planting. Let's back up and
talk about modules from premises forward.
For this reason, along with the trouble Sam and Dave are taking to
attend, I believe we must talk about modules at the January meeting.
Happy to talk at the March meeting with Ihab and Kris, or anyone, as
well.
Re isolation, sandboxing - and modules.
Is there is a case for the ability to 'configure and freeze' a global object for sandboxing, SES and maybe modules. Indeed the 'restricted eval' can be seen as more specific case of an eval which takes a 'configured and frozen global' environment. With a frozen global all bindings should be able to be resolved at the time eval is called. Effectively, restricted evaled code will have 'const x = <object>' binding added to it's scope - where 'x' is a
property from the configured global object.
N.B - if a restricted eval takes a second param as a string to configure the 'global environment' for the evaled code then it would avoid the closure peeking issue.
A key question is how a module system (and the ECMAScript engine generally) parcels out access to platform objects or capabilities (like XMLHttpRequest). Explicity via parameter passing or implicitly via a more 'dependency injection container' style using a configured (and frozen) 'global' object. With the latter approach the developer could configure a 'global' object which hides the DOM with a jquery-ish module - and all modules imported (including modules importing module) could use the jquery module without explicity importing it.
First-class native modules would be great: typeof mymod -> "Module".
Though as has noted elsewhere - we need this functionality SRTL - it's crucial!
On Jan 11, 2010, at 8:38 AM, Mark S. Miller wrote:
On Mon, Jan 11, 2010 at 3:03 AM, Kevin Curtis <kevinc1846 at googlemail.com
wrote: Re isolation, sandboxing - and modules.
Is there is a case for the ability to 'configure and freeze' a
global object for sandboxing, SES and maybe modules. Indeed the
'restricted eval' can be seen as more specific case of an eval which
takes a 'configured and frozen global' environment. With a frozen
global all bindings should be able to be resolved at the time eval
is called. Effectively, restricted evaled code will have 'const x =
<object>' binding added to it's scope - where 'x' is a property from
the configured global object.N.B - if a restricted eval takes a second param as a string to
configure the 'global environment' for the evaled code then it would
avoid the closure peeking issue.What's the "closure peeking issue"?
I hate to jog your memory on this, since you seem to have forgotten,
which must be a happier state than remembering:
peter.michaux.ca/articles/module-pattern-provides-no-privacy-at-least-not-in-javascript-tm
Fixed in Firefox 3.5, even with two-arg eval still present.
Just by following the ES3 book, we should not add a second argument to
eval in the future. Chapter 15 intro beefed up language in ES1 and 2
that was weak about implementations adding arguments to standardized
builtins. It's a no-no.
So any better eval will have to be eval.better() or Object.betterEval
or some such name added in a safer-to-extend object than the global
object or any standardized builtin's prototype object.
Brendan Eich wrote:
On Jan 10, 2010, at 9:30 PM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
On Jan 10, 2010, at 1:14 AM, Kevin Curtis wrote:
From SecureEcmaScript proposal: 6. The top level binding of this in an evaled Program is not the global object, but rather a frozen root object containing just the globals defined in the ES5 spec.
For many current applications, the frozen |this| object is not necessary or desirable in global code. The essential characteristic of modules, isolation for each module's "inside" from unimported effects of other modules, does not necessarily mean no mutation of primordial objects.
On the contrary, it does necessarily mean that. If you can mutate primordial objects, then there is no isolation of any module. There may be a reduction in the possibilities for accidental interference between modules, but that should be distinguished from isolation.
Who said primordial objects are shared between modules?
Having separate copies of primordial objects for each module is not sufficient to ensure isolation. If one module has access to some object obj of another, it can also get access to that object's prototype chain using Object.getPrototypeOf(obj), or obj.constructor.prototype.
OTOH, I was incorrect in saying that mutable primordials necessarily preclude isolation. It would be possible to virtualize mutations to a module's primordials so that they are only visible to that module, in the same way that Valija does. I don't favour that approach because it is very much more complicated.
Mark S. Miller wrote:
On Mon, Jan 11, 2010 at 3:03 AM, Kevin Curtis <kevinc1846 at googlemail.com>wrote:
Re isolation, sandboxing - and modules.
Is there is a case for the ability to 'configure and freeze' a global object for sandboxing, SES and maybe modules. Indeed the 'restricted eval' can be seen as more specific case of an eval which takes a 'configured and frozen global' environment. With a frozen global all bindings should be able to be resolved at the time eval is called. Effectively, restricted evaled code will have 'const x = <object>' binding added to it's scope - where 'x' is a property from the configured global object.
N.B - if a restricted eval takes a second param as a string to configure the 'global environment' for the evaled code then it would avoid the closure peeking issue.
What's the "closure peeking issue"?
code.google.com/p/google-caja/wiki/EvalBreaksClosureEncapsulation
David-Sarah Hopwood wrote:
Brendan Eich wrote:
On Jan 10, 2010, at 9:30 PM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
On Jan 10, 2010, at 1:14 AM, Kevin Curtis wrote:
From SecureEcmaScript proposal: 6. The top level binding of this in an evaled Program is not the global object, but rather a frozen root object containing just the globals defined in the ES5 spec. For many current applications, the frozen |this| object is not necessary or desirable in global code. The essential characteristic of modules, isolation for each module's "inside" from unimported effects of other modules, does not necessarily mean no mutation of primordial objects. On the contrary, it does necessarily mean that. If you can mutate primordial objects, then there is no isolation of any module. There may be a reduction in the possibilities for accidental interference between modules, but that should be distinguished from isolation.
Who said primordial objects are shared between modules?
Having separate copies of primordial objects for each module is not sufficient to ensure isolation. If one module has access to some object obj of another, it can also get access to that object's prototype chain using Object.getPrototypeOf(obj), or obj.constructor.prototype.
Correction: obj.constructor[.prototype] gives access to the constructor chain. But that doesn't really affect my argument, if constructors are mutable.
David-Sarah Hopwood wrote:
David-Sarah Hopwood wrote:
Brendan Eich wrote:
On Jan 10, 2010, at 9:30 PM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
For many current applications, the frozen |this| object is not necessary or desirable in global code. The essential characteristic of modules, isolation for each module's "inside" from unimported effects of other modules, does not necessarily mean no mutation of primordial objects.
On the contrary, it does necessarily mean that. If you can mutate primordial objects, then there is no isolation of any module. There may be a reduction in the possibilities for accidental interference between modules, but that should be distinguished from isolation.
Who said primordial objects are shared between modules?
Having separate copies of primordial objects for each module is not sufficient to ensure isolation. If one module has access to some object obj of another, it can also get access to that object's prototype chain using Object.getPrototypeOf(obj), or obj.constructor.prototype.
Correction: obj.constructor[.prototype] gives access to the constructor chain.
Ignore this; there was nothing to be corrected here.
So, FF3.5 has resurrected the sandboxed eval with the second 'global' object parameter - as the closure peeking issue has been fixed. (The second param is a live object rather than a string). And thus if the second param object is frozen (and the primordials and their prototypes etc frozen) FF3.5 eval could act as a restricted eval.
Was there anything - now the closure issue has been fixed - that argues against making this sandboxed eval a standard (somewhere). (Though my preference is for frozen primordials as standard in a betterEval).
Kevin Curtis wrote:
So, FF3.5 has resurrected the sandboxed eval with the second 'global' object parameter - as the closure peeking issue has been fixed. (The second param is a live object rather than a string).
I gather, then, that there has been no change in Mozilla developers' practice of adding unilateral language extensions without consulting anyone, and in particular without consulting this list.
On Jan 11, 2010, at 4:37 PM, David-Sarah Hopwood wrote:
Kevin Curtis wrote:
So, FF3.5 has resurrected the sandboxed eval with the second
'global' object parameter - as the closure peeking issue has been fixed. (The
second param is a live object rather than a string).I gather, then, that there has been no change in Mozilla developers' practice of adding unilateral language extensions without consulting
anyone, and in particular without consulting this list.
Get your facts straight, and get off your high horse.
The second argument to eval has been a Mozilla extension since 1998 at
least, it predates ES3:
bonsai.mozilla.org/cvsblame.cgi?file=mozilla/js/src/jsobj.c&rev=3.2 (1998-4-23 cvs commit, from a Netscape-internal cvs repo)
The only reason it was kept in Firefox 3.5 and 3.6 was for
compatibility with add-ons and applications built on the codebase:
bugzilla.mozilla.org/show_bug.cgi?id=442333 (removal of second
arg)
bugzilla.mozilla.org/show_bug.cgi?id=457068 (report of broken
add-ons)
It is going away for Firefox 3.7:
On Jan 11, 2010, at 10:53 AM, David-Sarah Hopwood wrote:
Who said primordial objects are shared between modules?
Having separate copies of primordial objects for each module is not sufficient to ensure isolation. If one module has access to some
object obj of another, it can also get access to that object's prototype
chain using Object.getPrototypeOf(obj), or obj.constructor.prototype.
I meant what I wrote: [w]ho said primordial objects are shared between
modules? Shared by passing objects, or by fiat in the implementation,
does not matter. Isolation does not require frozen primordials, no
matter how often you assume it does to conclude that it does.
Adam Barth's system of isolated heaps is similar to some of Mozilla's
wrappers, which can be used to isolate effects as well as propagate
them. Wrappers or membranes are another way than frozen primordials to
isolate.
Your assertion that isolation requires frozen primordials is simply
not true in general, but of course it is if you assume it for some
particular reason that is a choice among several design alternatives.
Better to argue why your preferred alternative is better, than to
assert that it is the only way to isolate.
On Jan 11, 2010, at 4:56 PM, Brendan Eich wrote:
The second argument to eval has been a Mozilla extension since 1998
at least, it predates ES3:bonsai.mozilla.org/cvsblame.cgi?file=mozilla/js/src/jsobj.c&rev=3.2 (1998-4-23 cvs commit, from a Netscape-internal cvs repo)
From bugzilla.mozilla.org/show_bug.cgi?id=531675#c4 :
We started down this road in conversations in Ecma TC39 ... around
the time ES3 was under way. We were trying to incubate a "better eval".
This was discussed in Ecma committee at the time, but it didn't make
it through the ES3 process, and we did not then remove it. Failure to
remove it at that point is something you could blame Mozilla JS
hackers for, I agree (I'll take some of that, although I was keeping
my distance in order to focus on mozilla.org founding work at the time).
But that's water way under the bridge, and frankly, it's a risk of
implementing prototype features that developers then come to depend
on. But it's Mozilla's albatross, not Ecma's and not es-discuss fodder
to rehash further. It's a cost of business unless one only ever
extends open source that never "ships" or is otherwise used or tested
much, which defeats the purpose of prototyping.
We will remove eval's second argument as soon as we can. I do not
think we should try to extend ES with two-arg eval, as I wrote
recently. This leaves us with eval.hermetic/eval.spawn or some other
extension point.
Brendan Eich wrote:
On Jan 11, 2010, at 4:37 PM, David-Sarah Hopwood wrote:
Kevin Curtis wrote:
So, FF3.5 has resurrected the sandboxed eval with the second 'global' object parameter - as the closure peeking issue has been fixed. (The second param is a live object rather than a string).
I gather, then, that there has been no change in Mozilla developers' practice of adding unilateral language extensions without consulting anyone, and in particular without consulting this list.
Get your facts straight, and get off your high horse.
My facts are straight. FF3.5 replaced one extension with a different, incompatible one. That's just as bad (worse, actually) as adding a new extension. That it is intended to be temporary only slightly mitigates the error.
The only reason it was kept in Firefox 3.5 and 3.6 was for compatibility with add-ons and applications built on the codebase:
It wasn't kept; it was changed to something with different semantics (but, nonsensically, the same API signature).
The behaviour in 3.5 and 3.6 isn't even documented (developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/eval) and the documentation incorrectly states that the second argument has been removed. If you are going to make incompatible changes, please update the docs at the same time (or ideally, in advance).
Brendan Eich wrote:
On Jan 11, 2010, at 10:53 AM, David-Sarah Hopwood wrote:
Who said primordial objects are shared between modules?
Having separate copies of primordial objects for each module is not sufficient to ensure isolation. If one module has access to some object obj of another, it can also get access to that object's prototype chain using Object.getPrototypeOf(obj), or obj.constructor.prototype.
I meant what I wrote: [w]ho said primordial objects are shared between modules? Shared by passing objects, or by fiat in the implementation, does not matter.
If objects cannot be passed directly between modules without breaking encapsulation, then it's not a particularly useful module system. Passing only JSON objects, say, is not sufficient: it's necessary to be able to pass function objects, at least.
Isolation does not require frozen primordials, no matter how often you assume it does to conclude that it does.
What part of "I was incorrect in saying that mutable primordials necessarily preclude isolation." did you not understand?
Kevin Curtis wrote:
So, FF3.5 has resurrected the sandboxed eval with the second 'global' object parameter - as the closure peeking issue has been fixed. (The second param is a live object rather than a string). And thus if the second param object is frozen (and the primordials and their prototypes etc frozen) FF3.5 eval could act as a restricted eval.
FF3.5 eval is undocumented, but if I'm reverse-engineering the source code patch (hg.mozilla.org/releases/mozilla-1.9.1/rev/67944d1b207d) correctly, it still violates encapsulation.
A restricted eval should be specified from scratch, not based on what a poorly thought-out vendor extension happens to do.
It looks like the reanimated eval has finally had a steak driven through it's heart. RIP.
It's could be useful to learn from the experience that FF had with this feature in determining how a new eval.hermetic should behave. The sandbox use-case which i think prompted the second param is (i think) still valid. That some dev's used it as reflection mechanism was unexpected - like much of the webs evolution.
So, a new 'eval.hermetic' could be:
- 'restricted' i.e. "The top level binding of this in an [hermetic] evaled Program is not the global object, but rather a frozen root object containing just the globals defined in the ES5 spec."
- more general with a second 'global' object parameter - which can be frozen (mandatory or optional?).
It would be interesting to see if the upcoming Modules proposal from Ihab and Kris still requires a eval.hermetic and what it's semantics are. There is the opportunity of achieving two goals (SES and Modules) with one feature
- which could be relatively easy to implement.
The lexical_scope strawman looks very good.
So, it's possible that: eval.hermetic = "use strict"
- "use lexical scope" (which maybe subsumed by "use strict")
- top-level 'this' set to something which isn't the global object. Or removed (for eval.hermetic).
Maybe eval.hermetic could 'pioneer' taking global off the scope chain via an implicit "use lexical scope" (plus "use strict"). If eval.hermetic takes as a second parameter a 'global' object it could be used to configure the top-level lexical frame - whose bindings are implicity frozen. If no 'global' object is passed - then standard environment primordials are assumed (which may be frozen or at least sandboxed).
(For some reason i thought the lexical_scope proposal was about turning 'vars' into 'lets'. doh).
On Wed, Jan 13, 2010 at 1:51 AM, Kevin Curtis <kevinc1846 at googlemail.com> wrote:
The lexical_scope strawman looks very good. So, it's possible that: eval.hermetic = "use strict"
- "use lexical scope" (which maybe subsumed by "use strict")
- top-level 'this' set to something which isn't the global object. Or removed (for eval.hermetic).
This is roughly my intent. There would be little to distinguish a module's scope from that of a strict, lexical, function scope with arguments named by the caller. The closure of a module would be parented directly by a lexical scope containing the primordials of the context by which the module was constructed. Details and rationale forthcoming.
Kris Kowal
On Jan 11, 2010, at 7:42 PM, David-Sarah Hopwood wrote:
My facts are straight. FF3.5 replaced one extension with a different, incompatible one. That's just as bad (worse, actually) as adding a new extension. That it is intended to be temporary only slightly mitigates the error.
You wrote "adding", implying the second argument to eval was novel,
but now with this message you write "replaced". These are not the same
verbs; this is not exactly fair play. Were you really aware of the
age of eval(s, o) in Mozilla when you wrote your original message?
Anyway. The fact remains that we have supported eval(s, o) for over a
decade. In order to fix the closure scope leak bug, we made an
obscure, corner-case change that left most code working. Ignoring the
extension vs. standard issue, this is how compatibility and cleanup
happen: you break what seems already broken, and see what you can get
away with during a release process.
The way this was done definitely could have been better, but we could
not simply remove eval(s, o) by our own API compatibility in minor
release policy. Thanks for the reminder to update the docs. I'll nag
the responsible parties.
On Jan 11, 2010, at 7:49 PM, David-Sarah Hopwood wrote:
If objects cannot be passed directly between modules without breaking encapsulation, then it's not a particularly useful module system. Passing only JSON objects, say, is not sufficient: it's necessary to
be able to pass function objects, at least.
Catching up, trying not to rehash or reopen wounds...
I agree JSON is not enough, but frozen primordials could inhibit
adoption of modules.
Isolation does not require frozen primordials, no matter how often you assume it does to conclude that it does.
What part of "I was incorrect in saying that mutable primordials necessarily preclude isolation." did you not understand?
Sorry, I didn't mean to ignore what you wrote, but it was still not
enough. You adverted to the "virtualize mutations" alternative, but
then dismissed it as too complicated:
"It would be possible to virtualize mutations to a module's
primordials so that they are only visible to that module, in the same
way that Valija does. I don't favour that approach because it is very
much more complicated."
A couple of responses:
-
Complicated for whom? The complexity of virtualized mutations is a
burden on implementors, who are few and expert. It relieves the more
numerous JS hackers from having to revise existing code (sometimes
there's no money to do so). -
The highly popular Prototype library, and a lot of extant code,
modifying primordials. If all such code must be rewritten to work in/ with modules, then modules have a steep adoption hill to climb.
On Jan 11, 2010, at 8:11 PM, David-Sarah Hopwood wrote:
Kevin Curtis wrote:
So, FF3.5 has resurrected the sandboxed eval with the second
'global' object parameter - as the closure peeking issue has been fixed. (The
second param is a live object rather than a string). And thus if the second
param object is frozen (and the primordials and their prototypes etc frozen)
FF3.5 eval could act as a restricted eval.FF3.5 eval is undocumented, but if I'm reverse-engineering the
source code patch (hg.mozilla.org/releases/mozilla-1.9.1/rev/67944d1b207d) correctly, it still violates encapsulation.
What do you mean? Can you give an example?
On Sun, Jan 17, 2010 at 11:00 PM, Brendan Eich <brendan at mozilla.com> wrote:
On Jan 11, 2010, at 7:49 PM, David-Sarah Hopwood wrote:
If objects cannot be passed directly between modules without breaking
encapsulation, then it's not a particularly useful module system. Passing only JSON objects, say, is not sufficient: it's necessary to be able to pass function objects, at least.
Catching up, trying not to rehash or reopen wounds...
I agree JSON is not enough, but frozen primordials could inhibit adoption of modules.
Isolation does not require frozen primordials, no
matter how often you assume it does to conclude that it does.
What part of "I was incorrect in saying that mutable primordials necessarily preclude isolation." did you not understand?
Sorry, I didn't mean to ignore what you wrote, but it was still not enough. You adverted to the "virtualize mutations" alternative, but then dismissed it as too complicated:
"It would be possible to virtualize mutations to a module's primordials so that they are only visible to that module, in the same way that Valija does. I don't favour that approach because it is very much more complicated."
A couple of responses:
- Complicated for whom? The complexity of virtualized mutations is a burden on implementors, who are few and expert. It relieves the more numerous JS hackers from having to revise existing code (sometimes there's no money to do so).
Obviously, I will have many positive things to say about the Valija approach for accommodating legacy. In fact, it was invented in order to cope with the "highly popular Prototype library" you mention below. However, the picture is not as rosy as "a burden [only] on implementors". The semantics of computing between Valija contexts are complicated, in similar but different manner to how the semantics of JS across frames is complicated today. If there's interest, I can present Valija with slides 10-15 of < ses.json.org/millerses.pdf>.
- The highly popular Prototype library, and a lot of extant code, modifying primordials. If all such code must be rewritten to work in/with modules, then modules have a steep adoption hill to climb.
I don't quite understand this. Prototype does not currently work with modules, so some rewrite is necessary in any case. As long as we're talking about future Prototype, my impression is that they wanted to migrate away from mutating primordials eventually anyway.
On Jan 18, 2010, at 4:38 AM, Mark S. Miller wrote:
Obviously, I will have many positive things to say about the Valija
approach for accommodating legacy. In fact, it was invented in order
to cope with the "highly popular Prototype library" you mention
below. However, the picture is not as rosy as "a burden [only] on
implementors". The semantics of computing between Valija contexts
are complicated, in similar but different manner to how the
semantics of JS across frames is complicated today. If there's
interest, I can present Valija with slides 10-15 of <ses.json.org/millerses.pdf.
Perhaps Valija is not the last word on this approach :-/. There's the
system Adam Barth is developing -- have you checked that out?
- The highly popular Prototype library, and a lot of extant code,
modifying primordials. If all such code must be rewritten to work in/ with modules, then modules have a steep adoption hill to climb.I don't quite understand this. Prototype does not currently work
with modules, so some rewrite is necessary in any case. As long as
we're talking about future Prototype, my impression is that they
wanted to migrate away from mutating primordials eventually anyway.
Tobie et al. may want to, but I know many users of Prototype who do
not. We're talking about a large number of actual uses, some of which
might want to migrate into a module, not necessarily be used cross-
module. The cost of doing so is low if primordials in that module can
be mutated. It goes way up if they can't.
On Mon, Jan 18, 2010 at 8:42 AM, Brendan Eich <brendan at mozilla.com> wrote:
On Jan 18, 2010, at 4:38 AM, Mark S. Miller wrote:
Obviously, I will have many positive things to say about the Valija approach for accommodating legacy. In fact, it was invented in order to cope with the "highly popular Prototype library" you mention below. However, the picture is not as rosy as "a burden [only] on implementors". The semantics of computing between Valija contexts are complicated, in similar but different manner to how the semantics of JS across frames is complicated today. If there's interest, I can present Valija with slides 10-15 of < ses.json.org/millerses.pdf>.
Perhaps Valija is not the last word on this approach :-/. There's the system Adam Barth is developing -- have you checked that out?
Yes. AFAICT, it is solving a different problem.
- The highly popular Prototype library, and a lot of extant code, modifying primordials. If all such code must be rewritten to work in/with modules, then modules have a steep adoption hill to climb.
I don't quite understand this. Prototype does not currently work with modules, so some rewrite is necessary in any case. As long as we're talking about future Prototype, my impression is that they wanted to migrate away from mutating primordials eventually anyway.
Tobie et al. may want to, but I know many users of Prototype who do not. We're talking about a large number of actual uses, some of which might want to migrate into a module, not necessarily be used cross-module. The cost of doing so is low if primordials in that module can be mutated. It goes way up if they can't.
Huh? I don't understand this. If they wish to be in the same
mutated-primordial-sandbox as Prototype, as you indicate and seems likely, then it would not help them if Prototype were packaged as a module and modules were the unit of primordial-mutation-sandboxing. Why should they not just load the existing Prototype into their frame the old fashioned way?
Or, yes, they could do the Valija thing, in order to multiplex a frame among multiple sandboxes. But a Valija sandbox is not a module. I think we're confusing levels.
On Jan 18, 2010, at 8:51 AM, Mark S. Miller wrote:
Tobie et al. may want to, but I know many users of Prototype who
do not. We're talking about a large number of actual uses, some of
which might want to migrate into a module, not necessarily be used
cross-module. The cost of doing so is low if primordials in that
module can be mutated. It goes way up if they can't.Huh? I don't understand this. If they wish to be in the same mutated- primordial-sandbox as Prototype, as you indicate and seems likely,
then it would not help them if Prototype were packaged as a module
No, I wrote "migrate into a module" meaning be part of the inside of a
module -- not be packaged as a module.
On Jan 18, 2010, at 9:57 AM, Mark S. Miller wrote:
No, I wrote "migrate into a module" meaning be part of the inside of
a module -- not be packaged as a module.I don't get it. What do you have in mind?
What's not to get? If you use Prototype inside a module, it will
mutate "the primordials" -- whatever ones it finds on the global at
the end of its scope chain. If those primordials are frozen, game over.
Tons of JS on the web mutates primordials, e.g.:
www.google.com/codesearch?as_q=Array.prototype.\w%2B+%3D +&btnG=Search + Code &hl
en &as_lang
javascript &as_license_restrict=i&as_license=&as_package=&as_filename=&as_case= www.google.com/codesearch?hl=en&lr=&q="extend(Array.prototype"&sbtn=Search
For any such code to move into a module, that code wants mutable
primordials. For isolation these would be per-module, and to avoid
problems exporting functions, some kind of membrane to support
virtualized mutation or throw on mutation attempt would be required
around any exposed objects that lead back to in-module prototypes.
Or we could say "rewrite all your code" or "forget it". But that is
not a given.
I simply don't understand what you mean by the phrase "migrate into a module". What does this mean?
On Jan 18, 2010, at 10:20 AM, Mark S. Miller wrote:
I simply don't understand what you mean by the phrase "migrate into
a module". What does this mean?
Use on the inside of a module. I have code I want to put in a module.
It uses Prototype. That's all.
Why is this hard to understand? Are you assuming modules are small,
and/or consisting of new code only?
On Mon, Jan 18, 2010 at 10:25 AM, Brendan Eich <brendan at mozilla.com> wrote:
On Jan 18, 2010, at 10:20 AM, Mark S. Miller wrote:
I simply don't understand what you mean by the phrase "migrate into a module". What does this mean?
Use on the inside of a module. I have code I want to put in a module. It uses Prototype. That's all.
How would you express "putting code in a module"? I just don't have a
concrete idea what you mean. Could you show a program fragment?
Why is this hard to understand? Are you assuming modules are small,
Or at least, that module boundaries coincide with boundaries between separately written source files, as is the case with module systems I'm familiar with from other languages. For example, Java classes-as-modules.
and/or consisting of new code only?
Or at least a new revision of old code, in order to repackage the code to
do module-based import/export linkage, rather than the current practice of implicit linkage through shared global variables.
Since I do not yet understand what you are trying to say, I may be the wrong person to guess why I'm finding it hard to understand ;). Altogether, my best guess right now is that what you are calling a module is what I would call a sandbox.
On Jan 18, 2010, at 11:58 AM, Mark S. Miller wrote:
On Mon, Jan 18, 2010 at 10:25 AM, Brendan Eich <brendan at mozilla.com>
wrote: On Jan 18, 2010, at 10:20 AM, Mark S. Miller wrote:I simply don't understand what you mean by the phrase "migrate into
a module". What does this mean?Use on the inside of a module. I have code I want to put in a
module. It uses Prototype. That's all.How would you express "putting code in a module"? I just don't have
a concrete idea what you mean. Could you show a program fragment?
Copy and paste. I copy prototype-1.6.0.2.js into mybigfatmodule.js,
add my special sauce which makes good use of Prototype's extensions to
primordials such as Array.prototype, and then purvey it to the world.
Why is this hard to understand? Are you assuming modules are small,
Or at least, that module boundaries coincide with boundaries between
separately written source files, as is the case with module systems
I'm familiar with from other languages. For example, Java classes-as- modules.
Nothing prevents people from inline-expanding Prototype into their
code, crashing and carrying whatever they want. The codesearch hits I
linked earlier shows instances, including v8's raytrace.js benchmark.
Would a raytracer with inline-expanded, possibly hand-minimized
Prototype make a good module? Maybe, maybe not; I'm not judging, just
noticing that people do this sort of thing today on the Web. Modules
might reform all bad habits, but probably not -- and developers don't
all agree on your definition of "bad".
and/or consisting of new code only?
Or at least a new revision of old code, in order to repackage the
code to do module-based import/export linkage, rather than the
current practice of implicit linkage through shared global variables.
Precedent and developer conversations I've had strongly suggest that
some code wants mutable primordials on the inside of a module that can
be consumed without the mutations affecting the importer's primordials.
Since I do not yet understand what you are trying to say, I may be
the wrong person to guess why I'm finding it hard to understand ;).
Altogether, my best guess right now is that what you are calling a
module is what I would call a sandbox.
Could be. Is there a hard difference? It's not obvious.
Users definitely want isolated frame-like "modules". Some browsers
even support such things, with postMessage for safe inter-"module"
communication. It's a bit heavyweight, but to get back to the topic of
this sub-thread: is the only alternative frozen primordials? I think
not.
On Mon, Jan 18, 2010 at 12:14 PM, Brendan Eich <brendan at mozilla.com> wrote:
On Jan 18, 2010, at 11:58 AM, Mark S. Miller wrote:
On Mon, Jan 18, 2010 at 10:25 AM, Brendan Eich <brendan at mozilla.com>wrote:
On Jan 18, 2010, at 10:20 AM, Mark S. Miller wrote:
I simply don't understand what you mean by the phrase "migrate into a module". What does this mean?
Use on the inside of a module. I have code I want to put in a module. It uses Prototype. That's all.
How would you express "putting code in a module"? I just don't have a concrete idea what you mean. Could you show a program fragment?
Copy and paste. I copy prototype-1.6.0.2.js into mybigfatmodule.js, add my special sauce which makes good use of Prototype's extensions to primordials such as Array.prototype, and then purvey it to the world.
Why is this hard to understand? Are you assuming modules are small,
Or at least, that module boundaries coincide with boundaries between separately written source files, as is the case with module systems I'm familiar with from other languages. For example, Java classes-as-modules.
Nothing prevents people from inline-expanding Prototype into their code, crashing and carrying whatever they want. The codesearch hits I linked earlier shows instances, including v8's raytrace.js benchmark.
Would a raytracer with inline-expanded, possibly hand-minimized Prototype make a good module? Maybe, maybe not; I'm not judging, just noticing that people do this sort of thing today on the Web. Modules might reform all bad habits, but probably not -- and developers don't all agree on your definition of "bad".
and/or consisting of new code only?
Or at least a new revision of old code, in order to repackage the code to do module-based import/export linkage, rather than the current practice of implicit linkage through shared global variables.
Precedent and developer conversations I've had strongly suggest that some code wants mutable primordials on the inside of a module that can be consumed without the mutations affecting the importer's primordials.
Since I do not yet understand what you are trying to say, I may be the wrong person to guess why I'm finding it hard to understand ;). Altogether, my best guess right now is that what you are calling a module is what I would call a sandbox.
Could be. Is there a hard difference? It's not obvious.
Users definitely want isolated frame-like "modules". Some browsers even support such things, with postMessage for safe inter-"module" communication. It's a bit heavyweight, but to get back to the topic of this sub-thread: is the only alternative frozen primordials? I think not.
I never said they were. Whether Valija specifically is the right model for
separating primordial mutation, we can of course argue about. But first, I'm still trying to understand your meaning. Would you agree that the Valija sandbox is an example of the concept you are calling "module" above? If so, then fine. Obviously, given the investment we've made in Valija, I am not opposed to that model. If not, then I still do not understand your meaning.
On Jan 18, 2010, at 12:14 PM, Brendan Eich wrote:
On Jan 18, 2010, at 11:58 AM, Mark S. Miller wrote:
On Mon, Jan 18, 2010 at 10:25 AM, Brendan Eich <brendan at mozilla.com> wrote: On Jan 18, 2010, at 10:20 AM, Mark S. Miller wrote:
I simply don't understand what you mean by the phrase "migrate into a module". What does this mean?
Use on the inside of a module. I have code I want to put in a module. It uses Prototype. That's all.
How would you express "putting code in a module"? I just don't have a concrete idea what you mean. Could you show a program fragment?
Copy and paste. I copy prototype-1.6.0.2.js into mybigfatmodule.js, add my special sauce which makes good use of Prototype's extensions to primordials such as Array.prototype, and then purvey it to the world.
Why is this hard to understand? Are you assuming modules are small,
Or at least, that module boundaries coincide with boundaries between separately written source files, as is the case with module systems I'm familiar with from other languages. For example, Java classes-as-modules.
Nothing prevents people from inline-expanding Prototype into their code, crashing and carrying whatever they want. The codesearch hits I linked earlier shows instances, including v8's raytrace.js benchmark.
Would a raytracer with inline-expanded, possibly hand-minimized Prototype make a good module? Maybe, maybe not; I'm not judging, just noticing that people do this sort of thing today on the Web. Modules might reform all bad habits, but probably not -- and developers don't all agree on your definition of "bad".
and/or consisting of new code only?
Or at least a new revision of old code, in order to repackage the code to do module-based import/export linkage, rather than the current practice of implicit linkage through shared global variables.
Precedent and developer conversations I've had strongly suggest that some code wants mutable primordials on the inside of a module that can be consumed without the mutations affecting the importer's primordials.
Since I do not yet understand what you are trying to say, I may be the wrong person to guess why I'm finding it hard to understand ;). Altogether, my best guess right now is that what you are calling a module is what I would call a sandbox.
Could be. Is there a hard difference? It's not obvious.
Users definitely want isolated frame-like "modules". Some browsers even support such things, with postMessage for safe inter-"module" communication. It's a bit heavyweight, but to get back to the topic of this sub-thread: is the only alternative frozen primordials? I think not.
I agree with Brendan, we've actually been working on "module"-like behaviour with iframes in webkit, basically allowing a detached iframe to remain live as it is passed between documents. This basically provides a shared code/state repository across multiple pages. That said this may be a different model than the existing module specifications?
I think something that needs to be cleared up is whether we expect modules to be safely shared with untrusted code (i'm still not sure what people are thinking about this). The general model in my mind is that each module would be its own global object, with an api object that can be used to vend api to whoever has a reference to the module. eg. a very ad hoc example, without to much thought given to the API itself, just to describe the model
mymodule.js: // Code encapsulated in the module var bar = 4; function sqr(x) { return x * x; } function myFunction(foo) { return sqr(foo * bar); }
// Vend myFunction to the module api APIObject.someAPI = myFunction
someCode.js: // Get my module mymodule = importModule("mymodule.js"); // This should be asynchronous // A compelling use of an API alert(mymodule.someAPI(4));
Anyhoo, i was just planning on bringing up this model at the f2f next week
On Jan 18, 2010, at 12:27 PM, Mark S. Miller wrote:
Since I do not yet understand what you are trying to say, I may be
the wrong person to guess why I'm finding it hard to understand ;).
Altogether, my best guess right now is that what you are calling a
module is what I would call a sandbox.Could be. Is there a hard difference? It's not obvious.
Users definitely want isolated frame-like "modules". Some browsers
even support such things, with postMessage for safe inter-"module"
communication. It's a bit heavyweight, but to get back to the topic
of this sub-thread: is the only alternative frozen primordials? I
think not.I never said they were. Whether Valija specifically is the right
model for separating primordial mutation, we can of course argue
about. But first, I'm still trying to understand your meaning. Would
you agree that the Valija sandbox is an example of the concept you
are calling "module" above? If so, then fine. Obviously, given the
investment we've made in Valija, I am not opposed to that model. If
not, then I still do not understand your meaning.
I don't believe I've been unclear. I also don't believe I have to read
up on Valija to communicate with you. Let's meet in the middle.
JS has mutable primordials. Adding modules won't banish this feature,
even if you think mutating primordials should be avoided (ES5 makes it
possible to mutate without breaking things like for-in).
If you insist on frozen primordials for modules to be used, then we'll
have to define and agree on sandboxes. But whatever you call them, if
you miss the mark with frozen-primordial modules, users will not use
them and we'll have wasted our time.
Another possibility, with precedent in other languages, is two levels:
the outer module system, acyclic and generally bigger by unit; and the
inner one, with first-class modules. There is not good agreement on
the name for the outer thing. If you want we can say sandbox.
One could imagine cooperating modules sharing mutable primordials
within a sandbox, and of course not sharing primordials across the
sandbox boundary.
Again the point is that frozen primordials should not be dictated.
Sorry if this is annoyingly recapitulating Valija. The list is read by
many people, not all conversant, and in order to avoid assuming too
much, I believe we should try to work from broader precedent and first
principles. I'll look at Valija later today.
[Removed Mark's address from Cc to stop my stmp server from complaining]
On Jan 18, 2010, at 12:14 PM, Brendan Eich wrote:
Copy and paste. I copy prototype-1.6.0.2.js into mybigfatmodule.js, add my special sauce which makes good use of Prototype's extensions to primordials such as Array.prototype, and then purvey it to the world.
I think I mentioned before at a meeting-- I think we should address modules and isolation as separate concerns and likely separate constructs.
If you do that, you can construct new contexts and control explicitly which contexts modules get instantiated in. That way you don't have your modules tightly coupled with instantiations of e.g. the primordials (and there's no reason to limit this to just the primordials). This would also allow explicit control over multiple modules sharing contexts -- you don't just want isolation, you also want the ability to control when /not/ to isolate.
Of course, you also want sensible and convenient defaults, both for back-compat and to avoid infecting all code with the general case.
But say you want to use Prototype and a 3rd-party Prototype-based widget, but you also want to use a couple other libraries that expect the primordials to be left alone. You create a separate context for the former two modules & let 'em go to town.
Dave
PS I'm not claiming we should prevent people from copying and pasting a bunch of modules into one fat one, if that's what they want/need to do, but we also shouldn't prevent people from using separate modules separately & still controlling isolation. Separating modularity and isolation is a way to do that.
On Mon, Jan 18, 2010 at 12:43 PM, Brendan Eich <brendan at mozilla.com> wrote:
On Jan 18, 2010, at 12:27 PM, Mark S. Miller wrote:
Since I do not yet understand what you are trying to say, I may be the
wrong person to guess why I'm finding it hard to understand ;). Altogether, my best guess right now is that what you are calling a module is what I would call a sandbox.
Could be. Is there a hard difference? It's not obvious.
Users definitely want isolated frame-like "modules". Some browsers even support such things, with postMessage for safe inter-"module" communication. It's a bit heavyweight, but to get back to the topic of this sub-thread: is the only alternative frozen primordials? I think not.
I never said they were. Whether Valija specifically is the right model for separating primordial mutation, we can of course argue about. But first, I'm still trying to understand your meaning. Would you agree that the Valija sandbox is an example of the concept you are calling "module" above? If so, then fine. Obviously, given the investment we've made in Valija, I am not opposed to that model. If not, then I still do not understand your meaning.
I don't believe I've been unclear. I also don't believe I have to read up on Valija to communicate with you. Let's meet in the middle.
JS has mutable primordials. Adding modules won't banish this feature, even if you think mutating primordials should be avoided (ES5 makes it possible to mutate without breaking things like for-in).
If you insist on frozen primordials for modules to be used,
I am not yet insisting on anything. I am still trying to understand what you are talking about. If you have not been unclear, then my failure is my fault, fine. That doesn't help me understand.
then we'll have to define and agree on sandboxes. But whatever you call them, if you miss the mark with frozen-primordial modules, users will not use them and we'll have wasted our time.
Another possibility, with precedent in other languages, is two levels: the outer module system, acyclic and generally bigger by unit; and the inner one, with first-class modules. There is not good agreement on the name for the outer thing. If you want we can say sandbox.
One could imagine cooperating modules sharing mutable primordials within a sandbox, and of course not sharing primordials across the sandbox boundary.
Again the point is that frozen primordials should not be dictated.
I have not proposed to dictate this.
Sorry if this is annoyingly recapitulating Valija. The list is read by many people, not all conversant, and in order to avoid assuming too much, I believe we should try to work from broader precedent and first principles. I'll look at Valija later today.
Thank you. Once you and I understand each other, I'm sure we can proceed to
explain and argue without assuming a detailed understanding of Valija by the broader audience.
On Mon, Jan 18, 2010 at 12:54 PM, Mark S. Miller <erights at google.com> wrote:
On Mon, Jan 18, 2010 at 12:43 PM, Brendan Eich <brendan at mozilla.com> wrote:
Again the point is that frozen primordials should not be dictated. I have not proposed to dictate this.
I have, in my "modules_emaker_style" module strawman.
There may be good reasons to relax that, which we can discuss now or in the f2f. But that was my starting point: to propose the simplest and cleanest possible solution, then argue down from there based on legacy.
I think we all agree that mutating primordials is a legacy technique.
Ihab
On Mon, Jan 18, 2010 at 6:10 PM, Brendan Eich <brendan at mozilla.com> wrote:
On Jan 18, 2010, at 5:58 PM, ihab.awad at gmail.com wrote:
I think we all agree that mutating primordials is a legacy technique.
I'm trying not to mix opinions about best practices with what is likely on the Web for years to come.
Sure, but without a new direction to go, we'll end up where we're headed, which is a many-headed Hydra at best. So:
-
The proposal as written imagines a future where primordials are immutable; but
-
I have consciously imagined we will discuss ways to accommodate the current corpus on the Web.
Ihab
On Mon, Jan 18, 2010 at 17:58, <ihab.awad at gmail.com> wrote:
I think we all agree that mutating primordials is a legacy technique.
I do not agree with that. Yes, mutating primordials in ES5 should be prevented if you want to be able to share your and other people's code. The reason is simply that you will run into cases where you step on each others toes. However, with something like contexts or ES4 namespaces (putting on my flame retardant cloak) I think that mutating primordials provides a cleaner programming model.
Brendan Eich wrote:
On the contrary, it does necessarily mean that. If you can mutate primordial objects, then there is no isolation of any module. There may be a reduction in the possibilities for accidental interference between modules, but that should be distinguished from isolation.