CommonJS modules don't solve the global pollution problem, because they can't. We're gonna keep blowing off limbs until we acknowledge that there's a design flaw in the language and take some positive action at a semantic level to correct it.
Regards On Dec 4, 2009, at 5:20 AM, Irakli Gozalishvili wrote: > Hi Mark, > > After looking at your posts, I do have a feeling that what you actually > trying to solve is not a namespacing but modules scope encapsulation. > Besides they way you're proposing to solve this is not really suits well for > the interpreted language. I would recommend you to look into commonjs, ( > http://commonjs.org/, http://wiki.commonjs.org/wiki/Modules/) I think it > solves the problem nicely without extending language itself. One more > interesting to look at http://www.cmlenz.net/archives/2009/12/namespaces > > -- > Irakli Gozalishvili > Web: http://rfobic.wordpress.com/ > Phone: +31 614 205275 > Address: Taksteeg 3 - 4, 1012PB Amsterdam, Netherlands > > > On Fri, Dec 4, 2009 at 03:59, Mike Samuel <[email protected]> wrote: > >> 2009/12/3 Mark A. Ziesemer <[email protected]>: >>> On Thu, Dec 3, 2009 at 12:37 PM, Mike Samuel <[email protected]> >> wrote: >>> >>>> Thanks for responding in such detail. >>>> I have responded inline, but to summarize what I think I've understood >> so far: >>>> (1) This is a proposal for an added function, without any proposed >>>> syntactic sugar >>> >>> Agreed, it is a proposal for an added function. Not sure about the >>> proposed syntactic sugar. >>> >>>> (2) The function can be implemented as a library function as in your >> blog post >>> >>> Agreed, though this would only be for compatibility until implemented >>> natively. A similar example of this is >>> >> https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach#Compatibility >>> . >>> >>>> (3) The goal is to reduce the chance of unintentional namespace >>>> collisions by code that is aware of the namespace function. >>> >>> Agreed, though not only between code that is aware of the namespace >>> function, but also allowing code that is aware of the namespace >>> function to better package itself (use no more than 1 global >>> variable), to reduce the chance of collisions with code that is not >>> aware of the namespace function. >> >> Quite. But the collisions are reduced only one way with legacy code. >> If code is not aware of the namespace function, then it can still >> clobber code that is. >> >> >>>> (4) It is not a goal to prevent namespace collisions between code >>>> written before the namespace function and code written after. >>>> Specifically, if legacy code did "com = 'foo'" then namespacing would >>>> be broken for all subsequent code. >>> >>> Somewhat. Any children of "com" would no longer be accessible by >>> "com". However, any code within the closure(s) that was a child of >>> com could possibly continue working properly, but just not able to be >>> externally referenced. Furthermore, if something did run that >>> reassigned "com", as long as that other code was just using it >>> temporarily, the reference could be "backed up and restored". For >>> example: >> >> Ok, so code that is aware of legacy code that clobbers a namespace can >> workaround the fact as long as both don't depend on the namespace >> surviving after they've run. >> >>> >>> namespace("com.example.something"); >>> // com.example.something is further populated. >>> >>> // Legacy JS now needs to be included, which uses "com" as a temporary >>> String variable. >>> // We are aware of this, and will handle accordingly. >>> >>> // Backup: >>> var comBackup = com; >>> >>> // Allow legacy code to run: >>> legacyCode(); >>> // com now is "1234", but will actually never be referenced by the >>> legacy code again. Restore: >>> com = comBackup; >>> delete comBackup; >>> >>> // com.example.* can now be referenced as intended. >>> >>> This is already an issue and a practice with namespace variables, such >>> as "$" used in jQuery. See >>> http://docs.jquery.com/Using_jQuery_with_Other_Libraries . >> >> An issue that namespace() does not address. >> >>>> So is it your argument that both (prefixing and dotted path >>>> namespacing) are conventions that address the same problem, but that >>>> the java-esque package name convention is a better convention? >>> >>> Somewhat. Both conventions help to eliminate naming collisions. >> >> eliminate -> mitigate? >> >>> However, the "dotted path" namespacing respects the global namespace, >>> where as every namespace created using prefixing is another entry in >>> the global namespace. >> >> Now you get at most one global entry per TLD. >> >> >>> There have been some concerns that using the nested objects may affect >>> performance, due to having to resolve multiple entities. However, >>> I've not seen any results of any tests that show this to be true, or >>> at least not with any significant additional expense. This is further >> >> Here is a console session from the squarefree shell on FF3.5 >> >> (function () { var abs = Math.abs; var t0 = Date.now(); for (var i = >> 100000; --i >= 0;) { abs(-1); } var t1 = Date.now(); return t1 - t0; >> })() >> 9 >> var js = {}; js.lang = {}, js.lang.Math = { abs: Math.abs } >> [object Object] >> (function () { var t0 = Date.now(); for (var i = 100000; --i >= 0;) { >> js.lang.Math.abs(-1); } var t1 = Date.now(); return t1 - t0; })() >> 65 >> >> Using a 4 deep path vs a local variable results in about a 7x slowdown. >> >> >>> mitigated through "aliasing" as previously demonstrated. I think the >> >> True. This aliasing will of course defeat a lot of the dynamism, such >> as using getters to do lazy loading. >> I suppose minifiers and optimizers could introduce aliases at the top >> of a closure to do some optimization, but only if the namespace name >> is statically determinable. Essentially what is described at >> >> http://www.daveoncode.com/2009/12/01/custom-javascript-classes-packages-using-goog-provide-and-goog-require/ >> >>> same performance concerns could be valid with prefixing, as the large >>> number of objects created at the global level can also hinder >>> performance, as hash functions used in the implementation for the >>> lookups may become less-than-optimal for a large number of items. >>> Even if it doesn't hinder the performance of the runtime, consider >>> tools such as the DOM inspector in Firebug. The window works much >>> better with 10,000 objects stored in a tree structure with only 20 or >>> so objects at the top level, rather than having all 10,000 objects >>> displayed at once. >>> >>>> Have you quantified the cost of each module carrying their own >>>> namespace creating code? >>>> The bit in your blog about the minified form of the namespace function >>>> suggest that it is low. >>> >>> The issue isn't so much about the amount of code. One issue is that >> >> Code size is an issue for many people. >> >>> each module that uses a namespace function also needs to make sure >>> that such a function is properly named or namespaced as to not >>> conflict with a similar namespace function in other modules. It is >>> also difficult to encourage the use of namespacing when a proper >>> method to utilize namespacing is not readily available. I don't agree >>> that each module should have to include this additional boilerplate >>> code. >> >> They will until/if 90+% of browsers support your namespace function. >> >>>> And if the function is in the minimized code, then can't minifiers do >>>> a better job since they can do whole program analysis to use an >>>> identifier smaller than the 9 character namespace, whereas if >>>> "namespace" where externally defined, the 9 character name could not >>>> be shortened. >>> >>> I'm somewhat confused. While the implementation of "namespace" may be >>> minified, the reference to the "namespace" function itself should >>> never be minified. This is part of my proposal - it should be made >>> globally available. Also, if/once made part of the language standard, >>> the will be no need to include the implementation of the "namespace" >>> function, other than for backwards-compatibility, as mentioned above. >> >> Yes, but if they carry the code themselves then a code optimizer can >> convert >> function namespace(qname) { ... } >> namespace('foo.bar') = ... >> // many more >> to >> function a(qname) { ... } >> a('foo.bar') = ... >> // many more >> saving space when 7 * nCalls > namespace.toString().length >> >> I suppose if the namespace function is a const, they could provide a >> local short name by aliasing, so please ignore. >> >> >>>> Since we are talking about language extensions, we need not be limited >>>> by the approaches that are easy in ES3. >>>> We can consider approaches that use other language primitives (like >>>> lexical scopes in Ihab's module proposal) to address the same goals as >>>> namespace. >>> >>> Does this even need to be considered a language extension? Nothing >> >> ES-harmony is talking about language extension. >> >>> I'm proposing is changing the language specification - just making an >>> additional function available globally and by default. This will also >>> allow it to be easily "back-ported" (as with the Array extras, etc.), >>> allowing the function to be used to aid against an immediate and >>> growing issue (naming collisions, etc.) >> >> >> >>>> Let me make sure I understand. >>>> Let's say you have a file foo.js that inroduces one API element >>>> com.ziesemer.foo. There are two namespaces: >>>> com >>>> com.ziesemer >>>> as a result of >>>> namespace('com.ziesemer').foo = ...; >>>> >>>> com.ziesemer.foo is not a namespace, since it is not created as a >>>> result of the namespace function, right? >>> >>> I'm not necessarily encouraging this, but "foo" could be a function, >>> but could also act as another namespace level. For example, all of >>> the following could be valid: >>> >>> com.ziesemer.foo("bar!"); >>> com.ziesemer.foo.child(); >>> com.ziesemer.foo.a.b(); >>> >>>> So for namespaces to be dynamic, means it would be OK for com.ziesemer >>>> to be implemented in terms of a getter -- e.g. to allow lazy loading? >>> >>> I have to think more on this. Need to review the concept of "getters" >>> in the language. >> >> Section 8.12 of the spec defines the semantics. A good starting point >> might be 15.2.3.6 Object.defineProperty. >> >>>>> any reason to introduce artificial limitations to prevent doing so. >>>> >>>> There are more clients for javascript programmers than just >>>> programmers and interpreters. There are debugging tools, minifiers, >>>> IDE auto-completers, documentation generators, etc. >>> >>> I don't see anything that conflicts with this. This practice is >>> already being used increasingly, and I've not seen any related issues >>> - including with debugging tools e.g. Firebug, or minifiers such as >>> the YUI Compressor. >> >>>>>> Why is namespace not in a namespace? >>> >>>> Lots of systems require bootstrapping. In java, there is no paradox >>>> when it comes to which ClassLoader loaded the Class or ClassLoader >>>> classes? >>> >>> True. The same could be done as: >>> >>> var com = {}; >>> com.example = {}; >>> com.example.namespace = function(){ /* ... */ }; >>> >>> com.example.namespace("com.example.test"); >>> >>> The better argument against this is probably that then every library, >>> etc., that wants to namespace will have to call >>> "com.example.namespace(...)" instead of just "namespace(...)". While >>> not impossible, it seems silly to bury what should be such a >>> fundamental function. >> >> Perhaps I just don't understand why it is so fundamental. >> It seems that if OO namespacing becomes the norm, most code modules >> will look like >> (function () { >> // aliases to externs >> var foo = namespace('com.foo'); // or an imports object composed >> from import...as decls >> >> // core code >> >> // export definitions -- 1 use of namespace >> mixin(namespace('com.bar'), { export1: ..., export2: ... }) >> })() >> So it seems that it wouldn't really be fundamental in core code -- >> just idiomatic for import and export. >> >> >>>> I appreciate that you're trying to codify existing practice. I'm >>>> trying to help clarify the proposal by asking these questions. Lot's >>>> of existing practices (JSON handling and getElementsByClassName come >>>> to mind) have many subtle variants, so codifying is not a simple >>>> matter of stamping approval on a concensus -- you still have to tease >>>> out goals, enumerate candidates, discuss tradeoffs, understand legacy >>>> code, etc. >>> >>> Perfectly agreed and appreciated. >>> >>>> This seems like a non-sequitur. >>>> >>>> If two pieces of code do >>>> namespace('com.ziesemer') = ... >>>> >>>> namespace('com.jquery') = ... >>>> isn't the com object a shared concern? Why is it "just an object"? >>> >>> I guess I don't see the issue. Following the namespacing practice, >>> one shouldn't define anything that they don't "own". I could take >>> ownership of "com.ziesemer" and assign things to it, or re-assign it. >>> However, I don't own "com", so I shouldn't touch it. It is still just >>> an object, just not one that anyone should pretend to own. >> >> But you do touch it. You add a 'ziesemer' property. >> And if "ownership" is the right concept, on Rhino, it is owned by the >> local environment. >> >>>> Wouldn't it be problematic for code to do something like (using the >> .info TLD): >>>> var info = loadUserInfo(); >>>> >>>> namespace('info.ziesemer').foo = ...; >>> >>> Probably. However, using "info" as a top level variable was the first >> issue. >> >> Yep, just an example of another way for this to interact badly with legacy >> code. >> There are many other TLDs that might be names in the top level or IDs >> exported since window includes document.all on IE -- travel, museum, >> biz, int, us, etc. >> >>> Additionally, the goal for this proposal isn't necessarily to define >>> the namespacing standard - just the function that can be used to >>> create namespaces. Another standard - either along with or after this >>> one - may clarify this. Also, if everyone just standardized on this, >>> there would be no further work to do. (High hopes, I realize, but not >>> impossible, or anything that I think should delay this proposal.) >> >> I don't know quite what a "namespacing" standard would look like, but >> if your goal is to get large numbers of developers to do things "the >> right way", a standard is not the right way to go. Standards can only >> help a small group of developers coordinate, e.g. browser >> implementors. >> >> I'm not yet convinced that namespacing is the problem to solve -- it >> sounds like solving the module problem would moot namespacing. >> >> >>>> If the first module creates an object, then the second will not modify >>>> it. But the second is problematic in this case precisely because it >>>> assumes things about info that are not true. If it is just an object, >>>> instead of "an object that other packages can safely add properties to >>>> without changing the meaning of namespace respecting programs" then >>>> namespacing is broken. >>> >>> See above. I don't see any issues with both working together. >>> >>>> (I think in Rhino it's not just an object. If there's any com package >>>> on the classpath, it's actually an immutable java package item that >>>> allows Rhino to get at java classes.) >>> >>> Very true. However, again, this isn't an issue with the proposed >>> namespace function itself, but the standard for how namespaces are >>> created. >> >> True. It's hard to reason about how the namespace function should >> behave without considering one or more naming schemes. >> >> >>> IMO, the JavaPackage's of "com", etc., should be eliminated and >>> instead referenced through the existing "Packages" JavaPackage. I.E.: >>> "Packages.com.sun" instead of "com.sun". >> >> I don't understand Rhino internals well, but I think the two have >> subtly different meanings. >> I agree though. But Rhino and liveconnect do raise legacy concerns >> for java-esque naming schemes. >> >>>>> I would say that namespaces should definitely not be marked >>>>> "unconfigurable". A good JavaScript library, if it has nothing else >>>>> to do and no more purpose, should actually remove itself from memory, >>>>> and allow itself to be garbage collected. I don't see any reason to >>>>> introduce any barriers to allowing this. >>>> >>>> How would this be done in practice? >>>> How would a library know when to unload itself? >>> >>> I'd consider this to be out-of-scope of this discussion. However, >>> it's probably more of an issue of not "how this would be done", but >>> "it's probably the wrong approach, anyway". >> >> Ok, so supporting unloading of code modules is definitely not a goal >> of the namespace function. >> >>> Such code should just be handled in a closure, so the entire thing can >>> go out-of-scope and be GC'd when complete: >>> >>> (function(){ >>> // Stuff... >>> })(); >> >> But dependencies it loads and accesses via namespace(...) could not do >> that. >> Code that does not use namespace(...) to export don't require manual >> deallocation, but their dependencies do. >> >>> However, for the point of this discussion: >>> >>> namespace("com.example.myApp"); >>> namespace("com.example.helperA"); >>> namespace("com.example.helperB"); >>> >>> "myApp" needs to utilize "helperA" and "helperB", but only >>> temporarily. Additionally, during this time, "helperA" and "helperB" >>> may call each other, which is why they need to have a namespaced >>> reference defined outside of a closure. After this, "myApp" could >>> remain, with the "helpers" removed: >> >> Only if myApp knows it "owns" helperA and helperB in the sense you used >> above. >> >>> com.example.myApp.cleanupHelpers(); >>> >>> Where cleanupHelpers was previously defined as: >>> >>> com.example.myApp.cleanupHelpers = function{ >>> delete com.example.helperA; >>> delete com.example.helperB; >>> }; >>> >>> More appropriately, both helpers could define their own cleanup() >>> functions, that could delete themselves in the same way. >> >> Personally, I dislike imposing manual memory management on languages >> that have a garbage collector. >> But you're right that this is not a problem with the namespace >> function, just with code loading schemes that depend on the global >> scope. >> >> >>>> If another approach to managing namespace collisions were to do this >>>> better, would it be an argument against the OO namespacing approach? >>> >>> I wouldn't want to do anything to hinder further progress or >>> enhancements around this. However, I don't think anything new would >>> be an argument against what is being proposed. As mentioned >>> previously, many libraries (especially the better ones) are already >>> utilizing the OO namespacing approach. Right now, each library is >>> creating and using their own "namespace" function. Scripting uses >>> that currently aren't using a library must either consider using a >>> library to obtain a namespace function, or define one themselves - at >>> the risk of a naming collision for the namespace function itself, etc. >> >> Ok, but hermetic eval based loaders would allow those libraries to >> work and take advantage of any namespace function without losing the >> ability to choose your own name, and without adding anything to the >> global scope which makes collection difficult. >> >>> I'm hoping that a provided namespace function can become standardized >>> into the language, and made available at runtime to previous versions >>> as demonstrated above. >> >>>> Do we agree that the ability to use `with` with OO namespaces is not a >>>> feature of the proposal. >>> >>> Agreed, not a highlighted feature. It is something that probably >>> should still be listed on a FAQ page, etc., that helps explain the >>> usage and design, but also the previously mentioned links that show >>> why it is not the best idea and why the other methods of aliasing >>> should be used instead. >>> >>>> Java packages provide for many things. I am trying to understand via >>>> your analogy which you see this as providing. As far as I can tell, >>>> java packages provide: >>>> (1) access control via package private and JAR sealing >>>> (2) hierarchical addressing of classes >>>> (3) some degree of namespace separation, though separation can also >>>> be achieved by using multiple classloaders >>> >>> Even JAR sealing doesn't provide access control. Classes and methods >>> within a sealed package can still be called. Sealing just means that >>> additional classes in a sealed package can't be defined outside of the >>> same JAR. >> >>> I don't think this is really applicable to this proposal, though. >> >> Agreed. Not applicable. >> >>>>> I guess I would consider the "private" and "protected" keywords more >>>>> suited to "hiding" things than packages. Even then, these keywords >>>>> are seldom misunderstood, and should never be used for "security". A >>>>> little reflection can go a long way! >>>> >>>> I disagree with this. Reflection does not work around the access >>>> control rules unless the VM invoker explicitly opts out. See Joe-E as >>>> an example of security based on access running a subset of Java with >>>> reflection enabled. http://code.google.com/p/joe-e/ >>> >>> True - as long as these details are understood. I was just saying >>> that I see the "private" keyword being used way too often as a failed >>> "security measure". >> >> >> >>> -- >>> Mark A. Ziesemer >>> www.ziesemer.com >>> >> _______________________________________________ >> es-discuss mailing list >> [email protected] >> https://mail.mozilla.org/listinfo/es-discuss >> > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss -- Alex Russell [email protected] [email protected] BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723 _______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

