Addition of a global namespace function?

Mark A. Ziesemer online at mark.ziesemer.com
Thu Dec 3 18:12:16 PST 2009


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
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach#Compatibility
.

> (3) The goal is to reduce the chance of unintentional namespace
> collisions by code that is aware of the namespace function.

Agreed, though not only between code that is aware of the namespace
function, but also allowing code that is aware of the namespace
function to better package itself (use no more than 1 global
variable), to reduce the chance of collisions with code that is not
aware of the namespace function.

> (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
http://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.  http://code.google.com/p/joe-e/

True - as long as these details are understood.  I was just saying
that I see the "private" keyword being used way too often as a failed
"security measure".

--
Mark A. Ziesemer
www.ziesemer.com


More information about the es-discuss mailing list