Addition of a global namespace function?

Mike Samuel mikesamuel at gmail.com
Thu Dec 3 10:37:31 PST 2009


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


More information about the es-discuss mailing list