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 <[email protected]>: >> On Wed, Dec 2, 2009 at 5:26 PM, Mike Samuel <[email protected]> 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 http://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 >> (http://www.yuiblog.com/blog/2006/06/01/global-domination/ , >> http://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? > > >> http://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 >> https://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: >> http://en.wikipedia.org/wiki/Namespace_%28computer_science%29 . (This >> also happens to list a number of drawbacks against using the "prefix >> namespacing" approach as a work-around, mentioned at >> http://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. ( >> http://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. http://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 > [email protected] > https://mail.mozilla.org/listinfo/es-discuss -- Alex Russell [email protected] [email protected] BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723 _______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

