Re: Remarks about module import
I'm a bit late to this module party... On Tue, Aug 19, 2008 at 1:00 AM, Ingvar von Schoultz [EMAIL PROTECTED] wrote: From the descriptions it looks like this could instead use a syntax based on destructuring assignment, if es-harmony will have destructuring: var {toggle: t, set: s} = import ( fetchModule ('http://foo.com/someModule.js'), Are module and file synonymous? See http://dev.helma.org/wiki/Modules+and+Scopes+in+Helma+NG/ What do the contents of the http://foo.com/someModule.js file look like? fetchModule would need to work with the local file system for server-side work. What exactly does fetchModule return? Some kind of first-class Module class instance or is it returning the object which is being destructured? {document: doc, background: bg} What does this argument to import do? ); t(); [snip] Peter ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
On Mon, Aug 18, 2008 at 1:44 PM, [EMAIL PROTECTED] wrote: Hi folks, The module system proposals, especially the one here -- http://wiki.ecmascript.org/doku.php?id=proposals:modules Oh, a module party! Sorry I'm late and thanks to Peter Michaux for alerting me that I was missing out. Ihab, if you recall, I met you and The Mikes last December to talk about module systems. I really like the direction of this thread and thought I'd put in a couple cents. A lot of the things I want from a module system have already been mentioned, so some of this is just a reiteration of some of the great ideas that have been posed; some beg distinctions. We do not need to preserve notions of eval, particularly that the last statement evaluated be the module object. I think that's a great idea and vehicle for explicit exports, but consider this one: perhaps modules can conceptually be constructors for capability objects that are frozen and returned by some require function or, by extension, some syntax that ultimately calls said require function. Just to be explicit, I think that, if module A imports module B, module B must have a special scope chain and context object. Solely by virtue of having been imported, we could distinguish it from a legacy script, even if module A isn't a new-style module. The context object would be the module object itself, that you would add attributes to in order to provide exports. This would increase the parallelism between objects and modules. The scope chain from global to local would be: * builtins object * module scope * the self module * an anonymous function block scope I agree that the builtins object should not be the global window object that we all know and love. It should be a frozen capability object containing JavaScript primitives that can be expected and conveniently accessed in any programming environment: frozen versions of String, Number, Object, (is a Map still in?) c. Perhaps the browser can host a window module that we explicitly import. I think it is also reasonable for this scope to contain some additional primitives including log or print (since we no longer have to avoid colliding with window.print). The module scope, essentially analogous to IMPORTS__ in Caja, should contain the require function (if this function needs to be unique for each module, since in a lambda-based implementation it would need to implicitly be aware of the URL on which the module resides for module-relative require calls). It could also contain any imported names from an from module import * style import. This would permit module code to retrieve these values and would also prevent malicious modules from overwriting the client module's inner-workings. However, this might not be a good solution for two remaining concerns: for security, it would not prevent a malicious module from overwriting names imported from those modules imported before it; for verifiability, it would make it more difficult to construct compile-time checks for name errors. In this respect, I recognize a tension and am resigned to the final value judgement. The module scope could also contain a module variable that refers to the current module, plus moduleScope, and builtins as deemed fit. Also, the moduleUrl, like __FILE__ would be handy for introspection. The module itself could be in the scope chain. This would permit programmers to reference provided functions without explicating this or module. And, naturally, there would need to be an empty anonymous scope chain for private closure variables for the module. That's the kind of environment I believe JavaScript should wrap around modules when they're loaded. I think it's also important that module's be singleton by virtue of memoizing the ultimate require function. I say ultimate because this would be the function that requires a module from it's fully qualified URL. Which leads me to my thoughts about the require function's calling conventions. I believe that the require function should be a continuation, either implicit or explicit, that yields and blocks until the module has been loaded, or accepts a continuation as an optional argument. I also think that module's should be identified and loaded with URL's. There should be a notion of a module root, a base URL for script paths. I do not think that we should not support anything like a lookup chain of PATHs, since this would incur major performance problems as the user agent looks and fails to find modules in each successive PATH. There should be one, and it should be global, determined by the user agent, perhaps deferring to a script path defined somewhere in the HTML for browser agents. There should also be module relative paths. This would liberate module's from the names of the directories and domains that contain them, increasing reuse. The require function might also benefit from accepting a version number, although I think it would suffice to explicate that in the URL
Re: Remarks about module import
Peter, Can you provide concrete examples (something a few lines longer than a hello world module) which shows both the module and importer code? sink.js /** this module provides a `sink` function which allows the user to cause a DOM element to forward its events to one and only one, detachable Widget object that implements `./event.js#Signaler`. */ /* these are modules by the same author, in the same directory */ from ./urllib.js import urlJoin; from ./base.js import Set; /* this is a cross-browser compatibility layer */ from ./browser.js import normalizeEventName, browserEventName; /* presumably browser is a module provided by the browser in some * cross-browser compatible way. */ from chrome://js/browser.js import observe; /* using let or var makes a variable private to the module */ let widgetNs = urlJoin(__FILE__, '#widget'); // or let widgetNs = urlJoin(moduleUrl, '#widget'); let sinksAttribute = urlJoin(__file__, '#sinks'); /* the name __FILE__, moduleUrl, __file__, or __DIR__ * isn't as important as the behavior. It would not * be onerous to provide both module file and dir variables, * but dir can be inferred from file and is best * dealt with via urlJoin which handles both cases unless * the provider of __DIR__ is unscrupulous about the * final forward-slash. */ /* assigning to this makes it an export */ this.sink = function (element, widget, eventName) { if (element[widgetNs] element[widgetNs] != widget) { element[widgetNs].final(); } element[widgetNs] = widget; let sinks = element.getAttribute(sinksAttribute); element[sinksNs] = sinks; let normalizedEventName = normalizeEventName(eventName); let browserEventName = browserEventName(eventName); if (!sinks.has(normalizedEventName)) { observe(element, browserEventName, function () { let widget = this.target[widgetNs]; widget.signal(normalizedEventName, this); }); sinks.insert(normalizedEventName); } /* break reference cycles */ widget = undefined; element = undefined; }; index.js from ./sink.js import sink; // or let sink = require(./sink.js).sink; from http://jquery.com/dist/jQuery.10.1.js; import jQuery as $ from ./my-widget.js import MyWidget sink($('#widget'), MyWidget()); Kris Kowal ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
[EMAIL PROTECTED] wrote: An importer could use this as follows -- var doc = ...; var bg = ...; import of fetchModule('http://foo.com/someModule.js'), with document: doc, background: bg using t: toggle, s: set; From the descriptions it looks like this could instead use a syntax based on destructuring assignment, if es-harmony will have destructuring: var {toggle: t, set: s} = import ( fetchModule ('http://foo.com/someModule.js'), {document: doc, background: bg} ); t(); One advantage would be that people would remember this syntax easily, since it's useful elsewhere. As a side effect, one could then choose to use the returned object instead: var m = import ( fetchModule ('http://foo.com/someModule.js'), {document: doc, background: bg} ); m.toggle(); -- Ingvar von Schoultz ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
On Tue, Aug 19, 2008 at 1:00 AM, Ingvar von Schoultz [EMAIL PROTECTED] wrote: From the descriptions it looks like this could instead use a syntax based on destructuring assignment, if es-harmony will have destructuring: I expect es-harmony to have destructuring bind. var {toggle: t, set: s} = import ( fetchModule ('http://foo.com/someModule.js'), {document: doc, background: bg} ); t(); One advantage would be that people would remember this syntax easily, since it's useful elsewhere. As a side effect, one could then choose to use the returned object instead: var m = import ( fetchModule ('http://foo.com/someModule.js'), {document: doc, background: bg} ); m.toggle(); Good suggestions! I like it. -- Cheers, --MarkM ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
Also I strongly agree that a module should *not* implicitly capture the lexical scope in which it is imported. I don't think anyone proposed any such thing. Do you? Ihab's post said: ... Apologies if I caused confusion here -- I was merely trying to state strongly a conceptual desideratum regardless of whether or not it was proposed. Cheers, Ihab -- Ihab A.B. Awad, Palo Alto, CA ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
On Mon, Aug 18, 2008 at 4:46 PM, Brendan Eich [EMAIL PROTECTED] wrote: On Aug 18, 2008, at 1:44 PM, [EMAIL PROTECTED] wrote: whether modules should be like ES1-3's weak notion of program units or should be something new: purely lexical scope containers. I was making a weak reference ;) to the ES3 Program but picking and choosing. Plus my head is deep in the Caja world. Apologies for the lack of clarity. My proposal is the latter per your question: A module is an isolated lexical scope container, and contains no implicit references to any shared global object. This reasoning seems backwards. If modules are added in a first-class way to the JS, they present an opportunity to avoid the global objec utterly, and enforce true lexical scope. Since the Program nonterminal from ES1-3 is evaluated using a shared global object in browser embeddings, it cannot be restated using this lexical-scope-only idea of a module. Right, so yes, I agree entirely. Inside a module, introduced by some kind of explicit syntax, only lexical scope is allowed. No global properties are available. Typos in unqualified identifier expressions can be caught at compile time. Cats and dogs live together in peace ;-). Yup, live they do. :) That said, we in Caja land have worried about whether *some* default global properties should be made available -- objects that are essentially powerless like Function and Number, and which would be a pain in the neck to have to explicitly pass down to subordinate modules every time with every importModule statement. What this set of defaults would or should be is up in the air, mainly because Date would logically be one of them yet it is notably *not* powerless. Thanks!! Ihab -- Ihab A.B. Awad, Palo Alto, CA ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
On Aug 18, 2008, at 4:55 PM, David-Sarah Hopwood wrote: I really like the general approach and the simplicity of Ihab's proposal. Also I strongly agree that a module should *not* implicitly capture the lexical scope in which it is imported. I don't think anyone proposed any such thing. Do you? I'm not sure why 'provide' needs new syntax, though. Syntax is (a) often good UI; (b) special form expression where there's no library way to say what the special form says. Why should everything be lambda-coded? What if I change your bindings for module and provide? (Maybe I can't; please explain why not.) I'm not being snarky (or not merely ;-). The pre-Harmony extreme of no new syntax, ever is dead. Asking whether new syntax pays for itself is ok, but the question becomes vacuous when the only demonstration against new syntax begs questions about usability and integrity. /be ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
On Mon, Aug 18, 2008 at 5:17 PM, Brendan Eich [EMAIL PROTECTED] wrote: On Aug 18, 2008, at 5:02 PM, [EMAIL PROTECTED] wrote: That said, we in Caja land have worried about whether *some* default global properties should be made available -- Why couldn't they be imported from a standard module? Must everything be passed down? Maybe in Caja, but I don't see that as a requirement on successor ES standards. Even in Caja, it's possible for one module to import another. What needs to be passed down is *authority*, not the ability to execute code. But ok, yes, if people like the idea of using an importModule construct to get the Function and Number objects, say, then sure, that's a great solution. What it means essentially is that the importModule construct, plus some fetchModule service that knows where to find the primordial objects, together constitute the material provided to a module by default. If this can be made to work cleanly while allowing user-supplied fetchModule implementations that get module code from (say) a database or whatever, then that's peachy. Ihab -- Ihab A.B. Awad, Palo Alto, CA ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
Fwiw -- On Mon, Aug 18, 2008 at 5:13 PM, Brendan Eich [EMAIL PROTECTED] wrote: On Aug 18, 2008, at 4:55 PM, David-Sarah Hopwood wrote: I'm not sure why 'provide' needs new syntax, though. Syntax is (a) often good UI; (b) special form expression where there's no library way to say what the special form says. In my proposal, what I'm calling importModule needs to be a special form if it is to be able to insert bindings into the lexical scope in which it is called. Everything else can be done with just plain old function calls. Whether or not it *should* is a whole 'nother ball of wax of a different color. What if I change your bindings for module and provide? (Maybe I can't; please explain why not.) Any given instantiation of a module is always vulnerable in diverse and sundry ways to its importer. Whether my importer changed my bindings for the module loading mechanism is the least of my worries if I'm importing all the rest of my channels to the outside world from it. Ihab -- Ihab A.B. Awad, Palo Alto, CA ___ Es-discuss mailing list Es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Remarks about module import
On Mon, Aug 18, 2008 at 5:59 PM, Brendan Eich [EMAIL PROTECTED] wrote: On Aug 18, 2008, at 5:25 PM, [EMAIL PROTECTED] wrote: Even in Caja, it's possible for one module to import another. What needs to be passed down is *authority*, not the ability to execute code. I was asking, I'm happy with an answer. But what's the requirement, exactly? Can you give an example? I'll back into this topic, in a way. From MarkM's thesis, page 77, caption to figure 8.2 -- Authority is the Ability to Cause Effects. If 1) Bob has permission to talk to Alice, 2) Alice has permission to write /etc/passwd, and 3) Alice chooses to write there any text Bob asks her to, then Bob has authority to write /etc/passwd. Loading a module in itself *may* cause effects (e.g., if the code is retrieved via HTTP). Otherwise, by executing this code, the entity importing the module may only consume memory and CPU time; it gains no new authority that it did not have before. (And, strictly speaking, the authority to load code should properly be granted by the importer of a module.) This requirement is driven by the desire to eliminate *ambient* authority: a piece of code should not have abilities to cause effects that have not been explicitly granted to it. For example, in the Unix example, any process has the ambient authority to read a large subset of the files on the system, regardless of whether these are needed for the task at hand. To quote a classic example, when I write: cp x.txt y.txt the cp process can attempt to read /etc/passwd and, if successful, open a socket and send the contents to the evil.com server. Yet it needed only to read x.txt and write y.txt and, were it so confined, the damage it could cause would be limited to corrupting the contents of y.txt. This damage is consistent with a simple causal model: cp can only damage the things I tell it to work on, and nothing else. And finally, such damage, being narrowly constrained, is now such that there is practically no reasonable economic or other incentive for authoring a malicious cp. From MarkM's thesis, page 16: The Principle of Least Authority (POLA) recommends that you grant each program only the authority it needs to do its job [MS03]. and this, as I hopefully motivated, is why we need to be sure that a module gets authority only explicitly, from its invoker. A capability is just an object reference that conveys authority. Typically, it is an object that, directly or transitively, can cause effects such as modifying valuable data held by some module; making changes to stable storage; displaying information on an output device; reading an input device; using the network; etc. A deep vision of capability systems would be that, on a computer system, the ability to cause effects at a primitive level -- essentially, access to hardware devices -- is owned by some powerful module instances which attenuate that into fine-grained objects, each of which represents some reasonable chunk (e.g., creating a connection to a specific host, or writing to a specific rectangle of the screen, or communicating in read-only fashion with a specific USB mass storage device). Careful interaction between modules in the system, keeping POLA in mind, ensures that everyone gets just the authority they need. The wiring of capabilities can be done by module configuration, but an important source of wiring information is the end-user. A deep capability system exposes to the end-user the ability to divvy up their authority between the modules to which they have access. For example, given a stock tracking gadget module, I may create two instances: one to hold my private information about what stocks I own, and another that just displays some information I consider interesting. The first I keep to myself, but I publish the second on my public profile page. Importantly, the fact that these are two instances of the same code does not grant them the ability to communicate; since I have not wired up my private instance to anything in my public profile, I know that my data is safe. In fact, the classic rewriting of the cp example is to simply pass it file descriptors, rather than file names: cp x.txt y.txt Thus redefined, cp needs no ambient access to any files; everything it needs is in its arguments or its Unix file descriptors, and that is all provided by its parent process. POLA is satisfied. (The fact that pretty much all Unices give cp the ambient authority to do pretty much anything else, even under these circumstances, is, if one is to take a polemical ocap perspective, simply a bug.) I thought you suggested that a few built-ins (Function, Number, not Date) were safe to populate in a global scope, above a module's apparent top lexical scope. A safe (immutable, I hope) top-level. Do I have that right? Yes, that was my suggestion. Your post asserted that responsibility for naming a module belongs to the importer (requirer? ugh). That could be the whole truth,