Addition of a global namespace function?
forgot to cc es-discuss.
---------- Forwarded message ---------- From: Michael Haufe <tno at thenewobjective.com>
Date: Tue, Dec 1, 2009 at 10:18 PM Subject: Re: Addition of a global namespace function? To: "Mark A. Ziesemer" <online at mark.ziesemer.com>
Have you looked at the CommonJS modules proposal? wiki.commonjs.org/wiki/Modules/1.1
On Tue, Dec 1, 2009 at 10:59 PM, Mark A. Ziesemer <online at mark.ziesemer.com>wrote:
I'm sorry - I may very well be missing something, but I don't see how this is at all related (?). What I'm proposing would be somewhat related to the YAHOO.namespace function (developer.yahoo.com/yui/docs/YAHOO.html), though without being limited to children of the "YAHOO" global object. Actually, the YAHOO version and others would be able to utilize the version I'm proposing within their versions.
If the point is to prevent pollution of global code, the proposed module system solves that more securely since it can prevents 3rd party code from doing anything nasty. There is also a related package system they are discussing: wiki.commonjs.org/wiki/Packages
I've been burned in the past by bad libraries using this idea, so I'm weary of it admittedly. Peter Michaux wrote an excellent article on the subject here: peter.michaux.ca/articles/javascript-namespacing Though I don't agree with his solution of using an underscore naming convention, I believe he does justice in defining the problem.
Mark, I read your blog, and I don't quite understand the proposal. Apologies for dumping a whole bunch of questions on you all at once.
What is the goal of namespaces? To prevent one module from (unintentionally|intentionally|both) clobbering an API exported by another module?
What is a namespace? An object that can be consistently addressed by a dotted path after first read? A chain of property names starting from a container that should always return the same result after first read?
Why is namespace not in a namespace?
On Wed, Dec 2, 2009 at 5:26 PM, Mike Samuel <mikesamuel at gmail.com> wrote:
What is the goal of namespaces? To prevent one module from (unintentionally|intentionally|both) clobbering an API exported by another module?
I'm not sure using "modules" is the correct term in this context. However, the goal of JavaScript "namespacing" as I see it is to prevent one section of code from unintentionally clobbering another section of code, due to naming collisions. This could be combinations of code from one or more developers, organizations, or products.
Imagine a typical, modern web page. Consider www.mozilla.org. It appears quite clean with only 4 *.js files loaded: mozilla.org.js, jquery-1.3.2.min.js, jquery-ui-1.7.2.custom.min.js, and urchin.js (older version of Google analytics). The first 3 are already very well behaved, actually following the exact standard I'm proposing with nested namespaces, including:
jQuery jQuery.ui jQuery.ui.mouse jQuery.event (many other jQuery objects) org.mozilla.carousel org.mozilla.strings org.mozilla.augmentCommunityHovers org.mozilla.init org.mozilla.tabSwitch (other org.mozilla.*)
I'd actually prefer that "jQuery" was "com.jquery", but it is certainly an effort towards namespacing. For both jQuery.* and org.mozilla.*, my proposed namespace function could be used to help create these nested objects. Currently, each script needs to find a way to do this itself, or depend upon another library that provides an appropriate namespacing function. Mozilla's is:
/**
- Namespace */ if (typeof org == 'undefined') { var org = {}; }
org.mozilla = function() { /* ... */ }
With my proposed addition, this would simply be:
namespace("org").mozilla = function() { /* ... */ }
or even shorter:
namespace("org.mozilla").init = function() { /* ... */ }
urchin.js, on the other hand, could certainly use some better namespacing. The only convention used is that everything begins with "_u". There's no standard or anything else to discourage any other of many, many other JavaScript developers to also develop a common library that is prefixed with "_u". Furthermore, as this method of "namespacing" is not using nested objects, it is contributing towards global namespace pollution (www.yuiblog.com/blog/2006/06/01/global-domination , blogger.ziesemer.com/2007/10/respecting-javascript-global-namespace.html ).
mankz.com/code/GlobalCheck.htm shows Google Urchin as having 76 global variables, with 73 in the current version hosted at mozilla.org. Fortunately, Google seems to have paid attention to this, as their newer version (ga.js) places everything as a child of "_gat" (Google AnalyTics?). Again, I would have preferred something like "com.google.analytics", but this is definitely a significant improvement from before. ga.js is quite obfuscated, but it is clear that they are also using nested objects to achieve proper namespacing. As part of this, they are surely having to create these nestings someplace themselves, and could also benefit from the global namespace function that I am proposing.
This is not only an issue with web pages, but other products where JavaScript may be mashed together. This includes - but is not limited to - Mozilla Firefox and its extensions, as mentioned in the previously linked addons.mozilla.org/en-US/developers/docs/policies/reviews .
What is a namespace? An object that can be consistently addressed by a dotted path after first read? A chain of property names starting from a container that should always return the same result after first read?
For a general definition of a namespace, I'll defer to Wikipedia: en.wikipedia.org/wiki/Namespace_(computer_science) . (This also happens to list a number of drawbacks against using the "prefix namespacing" approach as a work-around, mentioned at peter.michaux.ca/articles/javascript-namespacing .)
In JavaScript, it seems that I and many others (including the above examples of mozilla.org, jQuery, and Google Analytics) agree that namespacing is best accomplished using nested objects, or a "dotted path" as you mentioned. There just isn't anything (yet) built-in to the language to support this beneficial practice.
I would contend that namespaces are, and should be dynamic - so that they do not always have to return the same result after the first read. I'm not saying that doing so is a bad practice, but I don't see any reason to introduce artificial limitations to prevent doing so. Also, as being discussed, a namespace in JavaScript really isn't anything special - it is one or more objects. "com.example.x.y.z" could hold a value, as well as acting as a namespace for other child namespaces or values. Again, I'm not stating that this is a good practice, but I don't see a need to prevent it.
Why is namespace not in a namespace?
Because the namespace function should be one of few that are "truly global", along with the likes of "eval", and global objects such as "Array" and "String". (Other global functions include (encode/decode)URI(Component), is(Finite/NaN), and parse(Float/Int). It could be argued that these should belong in a namespace, e.g. Math.* for the later ones.)
The namespace function should also be used to create the namespace that the namespace function would reside in - which quickly turns into a paradox.
From your blog:
In what sense are namespaces object-oriented? As I understand the term, object-orientation is a way of organizing a program around objects that exchange messages. There's nothing in this proposal that deals with messaging or objects -- it seems to be a hierarchical addressing scheme.
Maybe a better way to state this is that the proposed method of namespacing in JavaScript makes use of its OO support, namely objects supporting child properties and methods.
When you talk about namespace aliasing, should namespaces be treated as first class? If namespaces are aliasable, should they be marked unconfigurable to prevent property deletion or is that up to the namespace user?
Again, namespacing isn't anything "new", and is already being widely used as shown in examples above. I'm just proposing the addition of a global namespace function to make creating new namespaces easier and standardized.
The way they are currently being implemented is just through nested objects. I'd say that objects already are (or should be) considered "first class" in JavaScript, so namespaces should be as well.
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.
When you talk about using the "with" statement with namespaces, what problem are you trying to solve? Is this meant to act as a poor-man's java import? Are you aware of the forward-compatibility problems that "with" entails, and the effect it has on tools like YUI compressor, closure compiler, etc.?
I wasn't trying to solve any problem. I only mentioned this as an alternative, to show the benefits that the nested-object approach has for namespacing. I agree, the "with" statement probably causes more problems than it helps. ( www.yuiblog.com/blog/2006/04/11/with-statement-considered-harmful ) While I didn't show an actual example on my blog post, I did mention that the previous example would be better done within another function.
Here is correcting that. This:
with(com.ziesemer.myPackage){ name = 'Mark'; location = 'Wausau, WI'; alertHello(); }
would better be accomplished as something like:
(function(){ var czmp = com.ziesemer.myPackage; czmp.name = 'Mark'; czmp.location = 'Wausau, WI'; czmp.alertHello(); })();
You mention java packages, which provide namespacing, and information hiding. Is it a goal for this scheme to extend to support information hiding as well? If so, how?
I would not easily agree that Java packages provide information hiding
- though the definition of the term "hiding" is up for dispute. Java namespaces allow for organization, and help to prevent naming collisions. Java adds some extra features based on these namespaces, such as package access protection. There would be nothing to prevent JavaScript from adding something similar someday.
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!
cheers, mike
(I've used the term "JavaScript" throughout this reply. Really, I think JavaScript and ECMAScript could have been used interchangeably.)
-- Mark A. Ziesemer www.ziesemer.com
Mark,
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 (2) The function can be implemented as a library function as in your blog post (3) The goal is to reduce the chance of unintentional namespace collisions by code that is aware of the namespace function. (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.
cheers, mike
2009/12/2 Mark A. Ziesemer <online at mark.ziesemer.com>:
On Wed, Dec 2, 2009 at 5:26 PM, Mike Samuel <mikesamuel at gmail.com> wrote:
What is the goal of namespaces? To prevent one module from (unintentionally|intentionally|both) clobbering an API exported by another module?
I'm not sure using "modules" is the correct term in this context. However, the goal of JavaScript "namespacing" as I see it is to prevent one section of code from unintentionally clobbering another section of code, due to naming collisions. This could be combinations of code from one or more developers, organizations, or products.
I was using the term module just to mean an addressable piece of code that is loaded by a single invocation of a loader such as <script> or
eval. I don't think we disagree over anything but nomenclature.
Imagine a typical, modern web page. Consider www.mozilla.org. It appears quite clean with only 4 *.js files loaded: mozilla.org.js, jquery-1.3.2.min.js, jquery-ui-1.7.2.custom.min.js, and urchin.js (older version of Google analytics). The first 3 are already very well behaved, actually following the exact standard I'm proposing with nested namespaces, including:
jQuery jQuery.ui jQuery.ui.mouse jQuery.event (many other jQuery objects) org.mozilla.carousel org.mozilla.strings org.mozilla.augmentCommunityHovers org.mozilla.init org.mozilla.tabSwitch (other org.mozilla.*)
I'd actually prefer that "jQuery" was "com.jquery", but it is certainly an effort towards namespacing. For both jQuery.* and org.mozilla.*, my proposed namespace function could be used to help create these nested objects. Currently, each script needs to find a way to do this itself, or depend upon another library that provides an appropriate namespacing function. Mozilla's is:
/** * Namespace */ if (typeof org == 'undefined') { var org = {}; }
org.mozilla = function() { /* ... */ }
With my proposed addition, this would simply be:
namespace("org").mozilla = function() { /* ... */ }
or even shorter:
namespace("org.mozilla").init = function() { /* ... */ }
urchin.js, on the other hand, could certainly use some better namespacing. The only convention used is that everything begins with "_u". There's no standard or anything else to discourage any other of many, many other JavaScript developers to also develop a common library that is prefixed with "_u". Furthermore, as this method of "namespacing" is not using nested objects, it is contributing towards global namespace pollution (www.yuiblog.com/blog/2006/06/01/global-domination , blogger.ziesemer.com/2007/10/respecting-javascript-global-namespace.html ).
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?
mankz.com/code/GlobalCheck.htm shows Google Urchin as having 76 global variables, with 73 in the current version hosted at mozilla.org. Fortunately, Google seems to have paid attention to this, as their newer version (ga.js) places everything as a child of "_gat" (Google AnalyTics?). Again, I would have preferred something like "com.google.analytics", but this is definitely a significant improvement from before. ga.js is quite obfuscated, but it is clear that they are also using nested objects to achieve proper namespacing. As part of this, they are surely having to create these nestings someplace themselves, and could also benefit from the global namespace function that I am proposing.
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. 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.
This is not only an issue with web pages, but other products where JavaScript may be mashed together. This includes - but is not limited to - Mozilla Firefox and its extensions, as mentioned in the previously linked addons.mozilla.org/en-US/developers/docs/policies/reviews .
What is a namespace? An object that can be consistently addressed by a dotted path after first read? A chain of property names starting from a container that should always return the same result after first read?
For a general definition of a namespace, I'll defer to Wikipedia: en.wikipedia.org/wiki/Namespace_(computer_science) . (This also happens to list a number of drawbacks against using the "prefix namespacing" approach as a work-around, mentioned at peter.michaux.ca/articles/javascript-namespacing .)
Thanks for the link. I was interested more in how you define it in terms of JavaScript primitives than in how the concept is applied generally.
In JavaScript, it seems that I and many others (including the above examples of mozilla.org, jQuery, and Google Analytics) agree that namespacing is best accomplished using nested objects, or a "dotted path" as you mentioned. There just isn't anything (yet) built-in to the language to support this beneficial practice.
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.
I would contend that namespaces are, and should be dynamic - so that they do not always have to return the same result after the first read. I'm not saying that doing so is a bad practice, but I don't see
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?
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?
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.
Also, as being discussed, a namespace in JavaScript really isn't anything special - it is one or more objects. "com.example.x.y.z" could hold a value, as well as acting as a namespace for other child namespaces or values. Again, I'm not stating that this is a good practice, but I don't see a need to prevent it.
Why is namespace not in a namespace?
Because the namespace function should be one of few that are "truly global", along with the likes of "eval", and global objects such as
I'm not sure I understand what "truly global" means. Array and String are defined globally, but are accessible by code that has no global references: [].constructor, and (function () { return this.constructor }).call('') I don't think namespace is global in the same way. And I think that fact can be used to argue that, where it not for backwards-compatibility, they need not be global. Array and String are always defined because they can't be defined as library code. But namespace obviously isn't currently defined that way and can be implemented as library code.
"Array" and "String". (Other global functions include (encode/decode)URI(Component), is(Finite/NaN), and parse(Float/Int). It could be argued that these should belong in a namespace, e.g. Math.* for the later ones.)
The namespace function should also be used to create the namespace that the namespace function would reside in - which quickly turns into a paradox.
Lots of systems require bootstrapping. In java, there is no paradox when it comes to which ClassLoader loaded the Class or ClassLoader classes?
From your blog:
In what sense are namespaces object-oriented? As I understand the term, object-orientation is a way of organizing a program around objects that exchange messages. There's nothing in this proposal that deals with messaging or objects -- it seems to be a hierarchical addressing scheme.
Maybe a better way to state this is that the proposed method of namespacing in JavaScript makes use of its OO support, namely objects supporting child properties and methods.
Ok, so it's OO because it uses objects, instead of functional because it uses lexical scoping. It is also imperative because it modifies the local environment using side-effects visible to code in the same module instead of declarative.
When you talk about namespace aliasing, should namespaces be treated as first class? If namespaces are aliasable, should they be marked unconfigurable to prevent property deletion or is that up to the namespace user?
Again, namespacing isn't anything "new", and is already being widely used as shown in examples above. I'm just proposing the addition of a global namespace function to make creating new namespaces easier and standardized.
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.
The way they are currently being implemented is just through nested objects. I'd say that objects already are (or should be) considered "first class" in JavaScript, so namespaces should be as well.
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"?
Wouldn't it be problematic for code to do something like (using the .info TLD): var info = loadUserInfo();
namespace('info.ziesemer').foo = ...; 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.
(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.)
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? If another approach to managing namespace collisions were to do this better, would it be an argument against the OO namespacing approach?
When you talk about using the "with" statement with namespaces, what problem are you trying to solve? Is this meant to act as a poor-man's java import? Are you aware of the forward-compatibility problems that "with" entails, and the effect it has on tools like YUI compressor, closure compiler, etc.?
I wasn't trying to solve any problem. I only mentioned this as an alternative, to show the benefits that the nested-object approach has for namespacing. I agree, the "with" statement probably causes more problems than it helps. ( www.yuiblog.com/blog/2006/04/11/with-statement-considered-harmful ) While I didn't show an actual example on my blog post, I did mention that the previous example would be better done within another function.
Here is correcting that. This:
with(com.ziesemer.myPackage){ name = 'Mark'; location = 'Wausau, WI'; alertHello(); }
would better be accomplished as something like:
(function(){ var czmp = com.ziesemer.myPackage; czmp.name = 'Mark'; czmp.location = 'Wausau, WI'; czmp.alertHello(); })();
Do we agree that the ability to use with
with OO namespaces is not a
feature of the proposal.
You mention java packages, which provide namespacing, and information hiding. Is it a goal for this scheme to extend to support information hiding as well? If so, how?
I would not easily agree that Java packages provide information hiding
I was referring to the fact that package-private affects access control (incl reflection unless the VM invoker turns it off). For that to be inviolable, you need to combine that with jar sealing.
- though the definition of the term "hiding" is up for dispute. Java namespaces allow for organization, and help to prevent naming collisions. Java adds some extra features based on these namespaces, such as package access protection. There would be nothing to prevent JavaScript from adding something similar someday.
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
I guess I would consider the "private" and "protected" keywords more suited to "hiding" things than packages. Even then, these keywords
They both do that. The presence of the keyword "private" in C++ does not mean that the word "friend" does not affect access control. In the same way both java packages in combination with the access level keywords specify access control for the language.
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. code.google.com/p/joe-e
On Dec 3, 2009, at 10:37 AM, Mike Samuel wrote:
Mark,
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 (2) The function can be implemented as a library function as in your blog post (3) The goal is to reduce the chance of unintentional namespace collisions by code that is aware of the namespace function. (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.
Personally, I don't think this is sufficient to solve the largest set of problems that users encounter with the language. Specifically, if entering a namespace does not prevent global pollution (i.e., omitting "var" still pollutes), then it seems to me like the proposal is something of a missed opportunity.
cheers, mike
2009/12/2 Mark A. Ziesemer <online at mark.ziesemer.com>:
On Wed, Dec 2, 2009 at 5:26 PM, Mike Samuel <mikesamuel at gmail.com> wrote:
What is the goal of namespaces? To prevent one module from (unintentionally|intentionally|both) clobbering an API exported by another module?
I'm not sure using "modules" is the correct term in this context. However, the goal of JavaScript "namespacing" as I see it is to prevent one section of code from unintentionally clobbering another section of code, due to naming collisions. This could be combinations of code from one or more developers, organizations, or products.
I was using the term module just to mean an addressable piece of code that is loaded by a single invocation of a loader such as <script> or eval. I don't think we disagree over anything but nomenclature.
Imagine a typical, modern web page. Consider www.mozilla.org. It appears quite clean with only 4 *.js files loaded: mozilla.org.js, jquery-1.3.2.min.js, jquery-ui-1.7.2.custom.min.js, and urchin.js (older version of Google analytics). The first 3 are already very well behaved, actually following the exact standard I'm proposing with nested namespaces, including:
jQuery jQuery.ui jQuery.ui.mouse jQuery.event (many other jQuery objects) org.mozilla.carousel org.mozilla.strings org.mozilla.augmentCommunityHovers org.mozilla.init org.mozilla.tabSwitch (other org.mozilla.*)
I'd actually prefer that "jQuery" was "com.jquery", but it is certainly an effort towards namespacing. For both jQuery.* and org.mozilla.*, my proposed namespace function could be used to help create these nested objects. Currently, each script needs to find a way to do this itself, or depend upon another library that provides an appropriate namespacing function. Mozilla's is:
/**
- Namespace */ if (typeof org == 'undefined') { var org = {}; }
org.mozilla = function() { /* ... */ }
With my proposed addition, this would simply be:
namespace("org").mozilla = function() { /* ... */ }
or even shorter:
namespace("org.mozilla").init = function() { /* ... */ }
urchin.js, on the other hand, could certainly use some better namespacing. The only convention used is that everything begins with "_u". There's no standard or anything else to discourage any other of many, many other JavaScript developers to also develop a common library that is prefixed with "_u". Furthermore, as this method of "namespacing" is not using nested objects, it is contributing towards global namespace pollution (www.yuiblog.com/blog/2006/06/01/global-domination , blogger.ziesemer.com/2007/10/respecting-javascript-global-namespace.html ).
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?
mankz.com/code/GlobalCheck.htm shows Google Urchin as having 76 global variables, with 73 in the current version hosted at mozilla.org. Fortunately, Google seems to have paid attention to this, as their newer version (ga.js) places everything as a child of "_gat" (Google AnalyTics?). Again, I would have preferred something like "com.google.analytics", but this is definitely a significant improvement from before. ga.js is quite obfuscated, but it is clear that they are also using nested objects to achieve proper namespacing. As part of this, they are surely having to create these nestings someplace themselves, and could also benefit from the global namespace function that I am proposing.
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. 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.
This is not only an issue with web pages, but other products where JavaScript may be mashed together. This includes - but is not limited to - Mozilla Firefox and its extensions, as mentioned in the previously linked addons.mozilla.org/en-US/developers/docs/policies/reviews .
What is a namespace? An object that can be consistently addressed by a dotted path after first read? A chain of property names starting from a container that should always return the same result after first read?
For a general definition of a namespace, I'll defer to Wikipedia: en.wikipedia.org/wiki/Namespace_(computer_science) . (This also happens to list a number of drawbacks against using the "prefix namespacing" approach as a work-around, mentioned at peter.michaux.ca/articles/javascript-namespacing .)
Thanks for the link. I was interested more in how you define it in terms of JavaScript primitives than in how the concept is applied generally.
In JavaScript, it seems that I and many others (including the above examples of mozilla.org, jQuery, and Google Analytics) agree that namespacing is best accomplished using nested objects, or a "dotted path" as you mentioned. There just isn't anything (yet) built-in to the language to support this beneficial practice.
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.
I would contend that namespaces are, and should be dynamic - so that they do not always have to return the same result after the first read. I'm not saying that doing so is a bad practice, but I don't see
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?
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?
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.
Also, as being discussed, a namespace in JavaScript really isn't anything special - it is one or more objects. "com.example.x.y.z" could hold a value, as well as acting as a namespace for other child namespaces or values. Again, I'm not stating that this is a good practice, but I don't see a need to prevent it.
Why is namespace not in a namespace?
Because the namespace function should be one of few that are "truly global", along with the likes of "eval", and global objects such as
I'm not sure I understand what "truly global" means. Array and String are defined globally, but are accessible by code that has no global references: [].constructor, and (function () { return this.constructor }).call('') I don't think namespace is global in the same way. And I think that fact can be used to argue that, where it not for backwards-compatibility, they need not be global. Array and String are always defined because they can't be defined as library code. But namespace obviously isn't currently defined that way and can be implemented as library code.
"Array" and "String". (Other global functions include (encode/decode)URI(Component), is(Finite/NaN), and parse(Float/Int). It could be argued that these should belong in a namespace, e.g. Math.* for the later ones.)
The namespace function should also be used to create the namespace that the namespace function would reside in - which quickly turns into a paradox.
Lots of systems require bootstrapping. In java, there is no paradox when it comes to which ClassLoader loaded the Class or ClassLoader classes?
From your blog:
In what sense are namespaces object-oriented? As I understand the term, object-orientation is a way of organizing a program around objects that exchange messages. There's nothing in this proposal that deals with messaging or objects -- it seems to be a hierarchical addressing scheme.
Maybe a better way to state this is that the proposed method of namespacing in JavaScript makes use of its OO support, namely objects supporting child properties and methods.
Ok, so it's OO because it uses objects, instead of functional because it uses lexical scoping. It is also imperative because it modifies the local environment using side-effects visible to code in the same module instead of declarative.
When you talk about namespace aliasing, should namespaces be treated as first class? If namespaces are aliasable, should they be marked unconfigurable to prevent property deletion or is that up to the namespace user?
Again, namespacing isn't anything "new", and is already being widely used as shown in examples above. I'm just proposing the addition of a global namespace function to make creating new namespaces easier and standardized.
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.
The way they are currently being implemented is just through nested objects. I'd say that objects already are (or should be) considered "first class" in JavaScript, so namespaces should be as well.
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"?
Wouldn't it be problematic for code to do something like (using the .info TLD): var info = loadUserInfo();
namespace('info.ziesemer').foo = ...; 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.
(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.)
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? If another approach to managing namespace collisions were to do this better, would it be an argument against the OO namespacing approach?
When you talk about using the "with" statement with namespaces, what problem are you trying to solve? Is this meant to act as a poor-man's java import? Are you aware of the forward-compatibility problems that "with" entails, and the effect it has on tools like YUI compressor, closure compiler, etc.?
I wasn't trying to solve any problem. I only mentioned this as an alternative, to show the benefits that the nested-object approach has for namespacing. I agree, the "with" statement probably causes more problems than it helps. ( www.yuiblog.com/blog/2006/04/11/with-statement-considered-harmful ) While I didn't show an actual example on my blog post, I did mention that the previous example would be better done within another function.
Here is correcting that. This:
with(com.ziesemer.myPackage){ name = 'Mark'; location = 'Wausau, WI'; alertHello(); }
would better be accomplished as something like:
(function(){ var czmp = com.ziesemer.myPackage; czmp.name = 'Mark'; czmp.location = 'Wausau, WI'; czmp.alertHello(); })();
Do we agree that the ability to use
with
with OO namespaces is not a feature of the proposal.You mention java packages, which provide namespacing, and information hiding. Is it a goal for this scheme to extend to support information hiding as well? If so, how?
I would not easily agree that Java packages provide information hiding
I was referring to the fact that package-private affects access control (incl reflection unless the VM invoker turns it off). For that to be inviolable, you need to combine that with jar sealing.
- though the definition of the term "hiding" is up for dispute. Java namespaces allow for organization, and help to prevent naming collisions. Java adds some extra features based on these namespaces, such as package access protection. There would be nothing to prevent JavaScript from adding something similar someday.
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
I guess I would consider the "private" and "protected" keywords more suited to "hiding" things than packages. Even then, these keywords
They both do that. The presence of the keyword "private" in C++ does not mean that the word "friend" does not affect access control. In the same way both java packages in combination with the access level keywords specify access control for the language.
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. code.google.com/p/joe-e
cheers, mike
(I've used the term "JavaScript" throughout this reply. Really, I think JavaScript and ECMAScript could have been used interchangeably.)
-- Mark A. Ziesemer www.ziesemer.com
es-discuss mailing list es-discuss at mozilla.org, mail.mozilla.org/listinfo/es-discuss
-- Alex Russell slightlyoff at google.com alex at dojotoolkit.org BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723
On Dec 3, 2009, at 3:01 PM, Alex Russell wrote:
Personally, I don't think this is sufficient to solve the largest set of problems that users encounter with the language. Specifically, if entering a namespace does not prevent global pollution (i.e., omitting "var" still pollutes), then it seems to me like the proposal is something of a missed opportunity.
I agree. Are there any proposals to add the capability of creating new top-level "scopes" (contexts?) and running a script in them, such that something like CommonJS modules could be implemented in user-land code? I imagine it as something like HTML5's importScripts() function (available to Workers only), but it would run the script (a single script) in a newly created top-level scope, and return that scope as an object from the function itself.
Patrick Mueller - muellerware.org
2009/12/3 Patrick Mueller <pmuellr at yahoo.com>:
On Dec 3, 2009, at 3:01 PM, Alex Russell wrote:
Personally, I don't think this is sufficient to solve the largest set of problems that users encounter with the language. Specifically, if entering a namespace does not prevent global pollution (i.e., omitting "var" still pollutes), then it seems to me like the proposal is something of a missed opportunity.
I agree. Are there any proposals to add the capability of creating new top-level "scopes" (contexts?) and running a script in them, such that something like CommonJS modules could be implemented in user-land code? I imagine it as something like HTML5's importScripts() function (available to Workers only), but it would run the script (a single script) in a newly created top-level scope, and return that scope as an object from the function itself.
There is the hermetic eval proposal that would not create new top-level scopes, with their attendant base Object constructor, but would allow experimentation with module systems that address the separation concerns resulting from global pollution.
Yes, strawman module system and proposals such as lexical scope are
cooking for Harmony:
strawman:modules, strawman:lexical_scope
These propose lower-level building blocks; ultimately there would be
syntactic sugar all the way up.
A namespace function that can be implemented in ES3 or even ES5
doesn't add much value, I agree -- the gaps to fill in the language
have to do with what ES1-5 leave out: better control over "program
fragments" that parse according to the spec's Program goal non-
terminal but which currently interact in embedding-specific ways, e.g.
successive <script> tags in a page.
What we really want are modules that isolate implementation details as
programmers desire, without name collisions in any object (even in
"the" or "my" global object).
I appreciate this thread as it has made me aware of the CommonJS effort which is of dear interest. I will certainly continue there, however I simply want to contribute the work I have done to find the ECMAScript way to manage packages and classes. For reference, and whatever value it may have, this is a bare-bones implementation which matches what you propose:
Documentation: support.livesite.net/products/es/docs/?doc=es1.doc Source: support.livesite.net/products/es/es1.js
And should there be any further interest, you can see a bit of what I have built upon this system: support.livesite.net/products/es
2009/12/3 Ryan Gies <ryan at livesite.net>:
On 12/03/2009 06:31 PM, Mike Samuel wrote:
2009/12/3 Ryan Gies
I appreciate this thread as it has made me aware of the CommonJS effort which is of dear interest. I will certainly continue there, however I simply want to contribute the work I have done to find the ECMAScript way to manage packages and classes. For reference, and whatever value it may have, this is a bare-bones implementation which matches what you propose:
Documentation: support.livesite.net/products/es/docs/?doc=es1.doc Source: support.livesite.net/products/es/es1.js
From my a quick look, it seems that you're also turning strings into package/namespace names at runtime. Are packages reified as javascript objects? Is it also a hierarchical addressing scheme? Is this something that would be helped or hindered by the namespace function?
Yes, packages are reified as objects and it is a hierarchical addressing scheme.
The proposed namespace function would be neither a benefit nor hindrance.
In my opinion, that which Mark has proposed as the 'namespace' function would be more aptly named 'vivify'--a very useful function indeed. The keyword 'namespace' is extremely valuable and ought be reserved for introducing scope into the parser rather than a runtime function.
On Thu, Dec 3, 2009 at 12:37 PM, Mike Samuel <mikesamuel at gmail.com> 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 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.
(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:
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 docs.jquery.com/Using_jQuery_with_Other_Libraries .
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. However, the "dotted path" namespacing respects the global namespace, where as every namespace created using prefixing is another entry in the global namespace.
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 mitigated through "aliasing" as previously demonstrated. I think the 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 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.
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.
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 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.
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.
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.
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.
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.)
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.
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 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".
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... })();
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:
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.
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.
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.
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. 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
2009/12/3 Mark A. Ziesemer <online at mark.ziesemer.com>:
On Thu, Dec 3, 2009 at 12:37 PM, Mike Samuel <mikesamuel at gmail.com> 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 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 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 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.
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, ( commonjs.org, wiki.commonjs.org/wiki/Modules) I think it solves the problem nicely without extending language itself. One more interesting to look at www.cmlenz.net/archives/2009/12/namespaces
-- Irakli Gozalishvili Web: rfobic.wordpress.com Phone: +31 614 205275 Address: Taksteeg 3 - 4, 1012PB Amsterdam, Netherlands
I see that Kris edited the first referenced page to remove the Hermetic Evaluation section (but not quick enough for me to notice!), rendering what's left with no proposals for the atomic bits to build the higher order bits. So are there any other proposals for alternative atomic bits like Hermetic Evaluation?
On Dec 3, 2009, at 3:52 PM, Brendan Eich wrote:
Yes, strawman module system and proposals such as lexical scope are cooking for Harmony:
strawman:modules, strawman:lexical_scope
These propose lower-level building blocks; ultimately there would be syntactic sugar all the way up.
Patrick Mueller - muellerware.org
On Fri, Dec 4, 2009 at 7:20 AM, Irakli Gozalishvili <rfobic at gmail.com> wrote:
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, (commonjs.org, wiki.commonjs.org/wiki/Modules) I think it solves the problem nicely without extending language itself. One more interesting to look at www.cmlenz.net/archives/2009/12/namespaces
If you or someone can show me an example of CommonJS modules being used in a web page, it would be very beneficial to myself and many - and may very well invalidate my entire proposal. However, I would first need a chance to review a full, concrete example - just as everyone has been reviewing my proposal here.
One point of my proposal that I'm unsure has received proper attention is that the type of namespacing I mentioned is already being used actively and increasingly online today - including in well-known libraries written by or with involvement from well-known JavaScript experts, such as Yahoo! UI (YUI) and jQuery. Even www.mozilla.org is already namespacing their JS code in "org.mozilla".
Defining the exact method of the namespacing was not even meant to be part of my proposal. For example, "jQuery." vs. "com.jquery.". However, they would all be supported by the proposed namespace function.
Without repeating all of my previous replies and the original proposal, I still think that such a namespace function would be a great benefit, even more than the other additions that have been made in the recent JavaScript versions since 1.5. Maybe it doesn't belong in the core ECMAScript specification itself, but as a JavaScript extension. Maybe there is a better name for the function to use than "namespace", in case there is concern that "namespace" should potentially be reserved for use as a keyword or another purpose in the future.
Another option to consider: Without necessarily proposing such a "namespace" function for inclusion into the base language, would there be a way to define / standardize that if a given named-function exists (whether it be "namespace", "createNS", etc.), that the API must be something similar to what has been described here? My proposal to have this standardized was so that "developer A" and "developer B" didn't both start to add "namespace" to their next greatest script library, where they are named the same but work differently / accept different arguments, etc.
-- Mark A. Ziesemer www.ziesemer.com
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.
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, ( commonjs.org, wiki.commonjs.org/wiki/Modules) I think it solves the problem nicely without extending language itself. One more interesting to look at www.cmlenz.net/archives/2009/12/namespaces
-- Irakli Gozalishvili Web: rfobic.wordpress.com Phone: +31 614 205275 Address: Taksteeg 3 - 4, 1012PB Amsterdam, Netherlands
On Fri, Dec 4, 2009 at 03:59, Mike Samuel <mikesamuel at gmail.com> wrote:
2009/12/3 Mark A. Ziesemer <online at mark.ziesemer.com>:
On Thu, Dec 3, 2009 at 12:37 PM, Mike Samuel <mikesamuel at gmail.com> 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
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 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
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. 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 es-discuss at mozilla.org, mail.mozilla.org/listinfo/es-discuss
es-discuss mailing list es-discuss at mozilla.org, mail.mozilla.org/listinfo/es-discuss
-- Alex Russell slightlyoff at google.com alex at dojotoolkit.org BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723
On Fri, Dec 4, 2009 at 10:41 AM, Alex Russell <alex at dojotoolkit.org> wrote:
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.
Is there any possibility that some solution at the semantic level could be back-ported to previous versions of the language, such as with the JavaScript 1.6 Array Extras? If so, and if further discussion is just needed by others to finalize a solution, I'm sure that I and others are willing to wait. If not, I think that something
- such as the namespace function I proposed - should continue to be considered as an "immediate" solution.
-- Mark A. Ziesemer www.ziesemer.com
On Fri, Dec 4, 2009 at 8:41 AM, Alex Russell <alex at dojotoolkit.org> wrote:
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.
ES5 allows one to enumerate all properties on primordial objects except the global (window) object, to attempt to delete all properties that are absent from a whitelist or die trying, and then to attempt freeze all these cleaned up primordials (including all objects reachable by traversal of remaining properties) or die trying. If both of these succeed...
ES5-strict enables to do a fully static scope analysis. Say one builds a static verifier for Program text that does nothing but reject text that either 1) is not a valid ES5-strict program unit, 2) has free variables, or 3) uses a direct eval operator. A "closed function" is a function that has no free variables. The natural rewrite of a module is as the body of a closed function, perhaps packaged in a larger closed expression or Program that would pass the above verifier. Because ES5-strict is statically scoped, such a verifier effectively removes the global object from the bottom of the scope chain of Programs that pass this verifier.
Given that primordials (other than the global object) are transitively frozen and that the above whitelist was adequately restrictive, each call of a closed function is fully isolated -- its connectivity to the world outside itself is fully under control of its caller. If the module-function's caller denies access to the global object, the indirect eval function, and to the Function constructor, then the module cannot pollute non-local state.
@Mark there are a lot of different implementations for usage in browser and all of them have + and - . Let me disagree with the fact that mozilla itself is using your proposed solutions, cause even though I'm not hired by mozilla I'm one part of the contributors community and quite updated with everything happening in there, besides mozilla has much better solution for solving the problem you're trying to solve and it has been there since 3.0 AFAR. It's called modules.
developer.mozilla.org/En/Using_JavaScript_code_modules
BTW as you are interested in Mozilla you might be interested in the fact that they are considering to implement some of the specs from commonjs for the jetpacks. Besides mozilla bespin's plugin infrastructure is also going to be fully based on commonjs packages and the work already in progress.
wiki.mozilla.org/Labs/Jetpack/JEP/29, wiki.mozilla.org/Labs/Bespin/StatusMeetings/2009-11-11
Back to the browser implementations here is:
one from me which is really simple and doesn't claims to be something special, it serves well my needs so far:
Gozala/experiments/tree/experimental/commonjs
And here is the more complicated one by sproutcore:
There is aslo some implementations for xulrunner:
one from me and another from Atul Varma (Mozillian)
BTW you might be interested to find out that bunch of mozillians are hanging out on commonjs mailing list. In case you want to discuss specs or implementations of commonjs I'de recommned to do it in commonjs mailing list.
P.S.: I do think you are getting it to personal and it really doesn't helps..
-- Irakli Gozalishvili Web: rfobic.wordpress.com Address: Taksteeg 3 - 4, 1012PB Amsterdam, Netherlands
On Fri, Dec 4, 2009 at 11:52 AM, Irakli Gozalishvili <rfobic at gmail.com> wrote:
besides mozilla has much better solution for solving the problem you're trying to solve and it has been there since 3.0 AFAR. It's called modules. developer.mozilla.org/En/Using_JavaScript_code_modules BTW as you are interested in Mozilla you might be interested in the fact that they are considering to implement some of the specs from commonjs for the jetpacks. Besides mozilla bespin's plugin infrastructure is also going to be fully based on commonjs packages and the work already in progress. wiki.mozilla.org/Labs/Jetpack/JEP/29, wiki.mozilla.org/Labs/Bespin/StatusMeetings/2009-11-11
This is all great, but as far as I can tell, nothing above is currently usable on the web. (But I see the below...)
Back to the browser implementations here is: one from me which is really simple and doesn't claims to be something special, it serves well my needs so far: Gozala/experiments/tree/experimental/commonjs And here is the more complicated one by sproutcore: sproutit/tiki There is aslo some implementations for xulrunner: one from me and another from Atul Varma (Mozillian)
This is probably the most promising alternative I've seen so far. I would have lots of questions around this, including how many of the concerns previously discussed here are addressed by this implementation.
Like I was proposing with the namespace function, I think that "require.js" would need to become "available by default" and as a standard for it to be utilized like it probably should - but still available for backporting (as with the Array extras, etc.) for the browsers and other implementations that don't yet have built-in support.
However, I'm content to let the rest of the community continue this discussion. This quickly became much more of a involved discussion than I expected / had hoped for.
-- Mark A. Ziesemer www.ziesemer.com
On Dec 4, 2009, at 9:38 AM, Mark S. Miller wrote:
On Fri, Dec 4, 2009 at 8:41 AM, Alex Russell <alex at dojotoolkit.org>
wrote: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.ES5 allows one to enumerate all properties on primordial objects except the global (window) object, to attempt to delete all properties that are absent from a whitelist or die trying, and then to attempt freeze all these cleaned up primordials (including all objects reachable by traversal of remaining properties) or die trying. If both of these succeed...
...then you still can't keep someone from plunking something into
window. for only their context. Not that you'd want to, but the
language still makes you work harder than not to do the right thing. A
missing "var" still screws the pooch.
ES5-strict enables to do a fully static scope analysis. Say one builds a static verifier for Program text that does nothing but reject text that either 1) is not a valid ES5-strict program unit, 2) has free variables, or 3) uses a direct eval operator. A "closed function" is a function that has no free variables. The natural rewrite of a module is as the body of a closed function, perhaps packaged in a larger closed expression or Program that would pass the above verifier. Because ES5-strict is statically scoped, such a verifier effectively removes the global object from the bottom of the scope chain of Programs that pass this verifier.
Again, it's good that we can do it now, but the default policy hasn't
changed, you you'll forgive me if I'm somewhat skeptical that opening
the door alone will bring in the thundering herds.
2009/12/4 Alex Russell <alex at dojotoolkit.org>:
On Dec 4, 2009, at 9:38 AM, Mark S. Miller wrote:
On Fri, Dec 4, 2009 at 8:41 AM, Alex Russell <alex at dojotoolkit.org> wrote:
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.
ES5 allows one to enumerate all properties on primordial objects except the global (window) object, to attempt to delete all properties that are absent from a whitelist or die trying, and then to attempt freeze all these cleaned up primordials (including all objects reachable by traversal of remaining properties) or die trying. If both of these succeed...
...then you still can't keep someone from plunking something into window. for only their context. Not that you'd want to, but the language still makes you work harder than not to do the right thing. A missing "var" still screws the pooch.
Such a var would not pass the verifier.
ES5-strict enables to do a fully static scope analysis. Say one builds a static verifier for Program text that does nothing but reject text that either 1) is not a valid ES5-strict program unit, 2) has free variables, or 3) uses a direct eval operator. A "closed function" is a function that has no free variables. The natural rewrite of a module is as the body of a closed function, perhaps packaged in a larger closed expression or Program that would pass the above verifier. Because ES5-strict is statically scoped, such a verifier effectively removes the global object from the bottom of the scope chain of Programs that pass this verifier.
Again, it's good that we can do it now, but the default policy hasn't changed, you you'll forgive me if I'm somewhat skeptical that opening the door alone will bring in the thundering herds.
Rewriters can bridge the gap between correct verifier and not-quite-correct code, by, e.g. introducing var declarations for free variables.
On Dec 4, 2009, at 1:52 PM, Mike Samuel wrote:
2009/12/4 Alex Russell <alex at dojotoolkit.org>:
On Dec 4, 2009, at 9:38 AM, Mark S. Miller wrote:
On Fri, Dec 4, 2009 at 8:41 AM, Alex Russell
<alex at dojotoolkit.org> wrote: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.ES5 allows one to enumerate all properties on primordial objects except the global (window) object, to attempt to delete all
properties that are absent from a whitelist or die trying, and then to attempt freeze all these cleaned up primordials (including all objects reachable by traversal of remaining properties) or die trying. If
both of these succeed......then you still can't keep someone from plunking something into
window. for only their context. Not that you'd want to, but the language
still makes you work harder than not to do the right thing. A missing "var"
still screws the pooch.Such a var would not pass the verifier.
ES5-strict enables to do a fully static scope analysis. Say one
builds a static verifier for Program text that does nothing but reject text that either 1) is not a valid ES5-strict program unit, 2) has free variables, or 3) uses a direct eval operator. A "closed function"
is a function that has no free variables. The natural rewrite of a module is as the body of a closed function, perhaps packaged in a larger closed expression or Program that would pass the above verifier. Because ES5-strict is statically scoped, such a verifier effectively removes the global object from the bottom of the scope chain of Programs that pass this verifier.Again, it's good that we can do it now, but the default policy hasn't changed, you you'll forgive me if I'm somewhat skeptical that
opening the door alone will bring in the thundering herds.Rewriters can bridge the gap between correct verifier and not-quite-correct code, by, e.g. introducing var declarations for free variables.
Rephrased slightly for the entertainment of 3rd parties:
me: the problem is that people can still omit var
you: everyone will run it through a verifier
me: programmers are still human, particularly web developers. They
don't run verifiers. In general we still have the problem.0
you: everyone will run it through a verifier
me: really? And if they're going to accept the constraint anyway,
wouldn't it be better if we just created a construct where the default
is changed?
you: but everyone can just run it through a verifier!
me: um...
Lawls.
On Dec 4, 2009, at 2:11 PM, Alex Russell wrote:
me: the problem is that people can still omit var you: everyone will run it through a verifier me: programmers are still human, particularly web developers. They
don't run verifiers. In general we still have the problem.0 you: everyone will run it through a verifier me: really? And if they're going to accept the constraint anyway,
wouldn't it be better if we just created a construct where the
default is changed? you: but everyone can just run it through a verifier! me: um...Lawls.
Let's back up.
You and I know we can't incompatibly change the language. So "use
strict" or better ("use lexical scope", or just the default in a
future opt-in version based on the Harmony proposals) will be
necessary to get the right non-default-but-built-into-browsers
behavior, where free variables are static errors. Anything else is a
new Web, e.g. Flash or Silverlight.
Unless you have a better idea?
2009/12/4 Alex Russell <alex at dojotoolkit.org>:
On Dec 4, 2009, at 1:52 PM, Mike Samuel wrote:
2009/12/4 Alex Russell <alex at dojotoolkit.org>:
On Dec 4, 2009, at 9:38 AM, Mark S. Miller wrote:
On Fri, Dec 4, 2009 at 8:41 AM, Alex Russell <alex at dojotoolkit.org> wrote:
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.
ES5 allows one to enumerate all properties on primordial objects except the global (window) object, to attempt to delete all properties that are absent from a whitelist or die trying, and then to attempt freeze all these cleaned up primordials (including all objects reachable by traversal of remaining properties) or die trying. If both of these succeed...
...then you still can't keep someone from plunking something into window. for only their context. Not that you'd want to, but the language still makes you work harder than not to do the right thing. A missing "var" still screws the pooch.
Such a var would not pass the verifier.
ES5-strict enables to do a fully static scope analysis. Say one builds a static verifier for Program text that does nothing but reject text that either 1) is not a valid ES5-strict program unit, 2) has free variables, or 3) uses a direct eval operator. A "closed function" is a function that has no free variables. The natural rewrite of a module is as the body of a closed function, perhaps packaged in a larger closed expression or Program that would pass the above verifier. Because ES5-strict is statically scoped, such a verifier effectively removes the global object from the bottom of the scope chain of Programs that pass this verifier.
Again, it's good that we can do it now, but the default policy hasn't changed, you you'll forgive me if I'm somewhat skeptical that opening the door alone will bring in the thundering herds.
Rewriters can bridge the gap between correct verifier and not-quite-correct code, by, e.g. introducing var declarations for free variables.
Rephrased slightly for the entertainment of 3rd parties:
me: the problem is that people can still omit var you: everyone will run it through a verifier me: programmers are still human, particularly web developers. They don't run verifiers. In general we still have the problem.0 you: everyone will run it through a verifier me: really? And if they're going to accept the constraint anyway, wouldn't it be better if we just created a construct where the default is changed? you: but everyone can just run it through a verifier! me: um...
No, this is a strawman.
For micky mouse applications, module systems don't matter. But they matter a great deal for complex applications that are trying to combine the work of many people into a coherent whole. Those projects tend to have someone who maintains a build system.
The goal of a module system is to provide separation. The person who bundles the modules into a program is the one who wants to guarantee separation. So the verifier/rewriter is run by the deployer of the application. Not the library writer or the UI developer. Just the build manager.
Not every project. Just complex projects where coordination requires module management.
On Dec 4, 2009, at 2:13 PM, Brendan Eich wrote:
On Dec 4, 2009, at 2:11 PM, Alex Russell wrote:
me: the problem is that people can still omit var you: everyone will run it through a verifier me: programmers are still human, particularly web developers. They
don't run verifiers. In general we still have the problem.0 you: everyone will run it through a verifier me: really? And if they're going to accept the constraint anyway,
wouldn't it be better if we just created a construct where the
default is changed? you: but everyone can just run it through a verifier! me: um...Lawls.
Let's back up.
You and I know we can't incompatibly change the language. So "use
strict" or better ("use lexical scope", or just the default in a
future opt-in version based on the Harmony proposals) will be
necessary to get the right non-default-but-built-into-browsers
behavior, where free variables are static errors. Anything else is a
new Web, e.g. Flash or Silverlight.Unless you have a better idea?
Nope. I'm only suggesting that we need to get to "use better_thing"
SRTL and that ES5 strict mode doesn't fix the problem in an
appreciable way for most content. I expect we're in agreement.
Alex Russell wrote:
Nope. I'm only suggesting that we need to get to "use better_thing" SRTL and that ES5 strict mode doesn't fix the problem in an appreciable way for most content. I expect we're in agreement.
Re SRTL and the scope/timeframes for ES6.
How about an ES6 which focuses on:
- removing cruft-weirdness. e.g. global on the scope chain.
- adding core runtime semantics which improve security, simplicity and speed. e.g "use lexical"/let, revised function, hermetic eval. And especially, first class support of modules without rewriting.
Sugar, decimal, operator overloading etc - all good things - can be ES7+. And build on a solid ES6 foundation.
If an iterator protocol goes in ES6 maybe it could take the form: Object.defineIterator(o, function() {...}); Same for catchalls: Object.defineCatchall(o, function() {...});
2009/12/7 Kevin Curtis <kevinc1846 at googlemail.com>:
Alex Russell wrote:
Nope. I'm only suggesting that we need to get to "use better_thing" SRTL and that ES5 strict mode doesn't fix the problem in an appreciable way for most content. I expect we're in agreement.
Re SRTL and the scope/timeframes for ES6.
How about an ES6 which focuses on:
- removing cruft-weirdness. e.g. global on the scope chain.
- adding core runtime semantics which improve security, simplicity and speed. e.g "use lexical"/let, revised function, hermetic eval. And especially, first class support of modules without rewriting.
Agreed. The verifying/rewriting approach can help people roll out applications with proper module support on legacy interpreters, but the committee should investigate approaches that moot the rewriters.
Sugar, decimal, operator overloading etc - all good things - can be ES7+. And build on a solid ES6 foundation.
One of the things that made ES5 meetings productive was a statement about what was and was not ES5: standardizing extensions and fixing quirks that are agreed upon by a majority of the major interpreters
Can you phrase the ES6/7 distinction in similar terms?
On Fri, Dec 4, 2009 at 6:31 AM, Patrick Mueller <pmuellr at yahoo.com> wrote:
I see that Kris edited the first referenced page to remove the Hermetic Evaluation section (but not quick enough for me to notice!), rendering what's left with no proposals for the atomic bits to build the higher order bits. So are there any other proposals for alternative atomic bits like Hermetic Evaluation?
Sorry about that. The proposal had some flaws that need to be addressed in a new proposal. I'm working on it with Ihab. The problem was that the proposal required the injected scopes names to be declared at time of parse/compile instead of time of execution, which made the module factory functions less reusable. The new proposal will probably look like:
var factory = XYZ(text, fileName_opt, lineNo_opt); var lastValue = factory(scopeInjected_opt);
For some value of XYZ. XYZ might involve creating a Context with some primordials. The primordials might have frozen or pre-frozen variations. There could be a separate system for constructing a set of primordials. There will certainly be a note that only the owned properties of the scopeInjected Object will be transferred into the evaluated scope. Whether the injected terms must be constants is up for debate.
Kris Kowal
I'd like to propose a "namespace()" function to the base ECMAScript language. (I previously thought about this only in terms of JavaScript, but I'm guessing it really belongs in ECMAScript?)
I've previously blogged about this at blogger.ziesemer.com/2007/10/respecting-javascript-global-namespace.html and blogger.ziesemer.com/2008/05/javascript-namespace-function.html , having actually become part of the review process for Firefox add-ons, being linked to from addons.mozilla.org/en-US/developers/docs/policies/reviews .
While it is easy enough to define and use such a namespace function without it being included in the base language, the same could be said for the new String.trim functions that were just recently added. I further feel that it would be very beneficial to have a "namespace" function declared in a standard rather than being used in an ad-hoc fashion, as this would hopefully discourage others from declaring a global "namespace" function that is unrelated or otherwise incompatible. Finally, I think that this would be an important addition, especially with the amount of JavaScript being combined into web pages today. (I could come up with many more reasons, but I think this is a pretty good summary to start with.)
I understand that at best, this would probably not appear until a later version of the specification. In the meantime, it could continue to be supported as a back-portable extension, such as the Array extras. However, most importantly, it would define this as part of the (future) "language standard".
Here is the actual function I am proposing, just so you don't have to click through:
var namespace = function(name, separator, container){ var ns = name.split(separator || '.'), o = container || window, i, len; for(i = 0, len = ns.length; i < len; i++){ o = o[ns[i]] = o[ns[i]] || {}; } return o; };
Example of use:
namespace("com.example.namespace"); com.example.namespace.test = function(){ alert("In namespaced function."); };
Or, as one statement:
namespace("com.example.namespace").test = function(){ alert("In namespaced function."); };
Either is then executed as:
com.example.namespace.test();
Thanks for your consideration.
-- Mark A. Ziesemer www.ziesemer.com