Addition of a global namespace function?

Mark A. Ziesemer online at mark.ziesemer.com
Wed Dec 2 21:11:06 PST 2009


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 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
).

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.

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 .)

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.  (
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();
})();

> 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


More information about the es-discuss mailing list