Namespaces as Sugar (was: complexity tax)
mjs at apple.com
Tue May 27 11:42:47 PDT 2008
On May 27, 2008, at 11:00 AM, Brendan Eich wrote:
> What's at issue is whether and why unqualified import matters in any
> object, even the global object only, since the NAS proposal did not
> allow unqualified import even at global level, and the use-case for
> unqualified import was dismissed as not compelling.
There's really 4 separable issues:
1) Namespacing of names at global scope (via lexically scoped
2) Unqualified import of names into global scope.
3) Namespacing of arbitrary object properties.
4) Unqualified import of namespaces for arbitrary object properties.
I would claim 1 and 2 are essential, 3 can be done by convention in
the absence of 4 (a la the NAS proposal) and 4 is unnecessary and
harmful to performance.
>>> That's an interesting idea, although we use namespace
>>> qualification along the prototype chain all over the place in ES4,
>>> and for what seem like good reasons.
>> Other languages with successful namespacing features don't have
>> such a mechanism, so I am dubious of the goodness of these ideas. I
>> am concerned that the namespace lookup algorithm for object
>> property access is too complicated.
> Agreed, this is the big issue. I share your concern, but the
> conservative approach (esp. with reference to C++) of throwing out
> non-global open namespaces looks like an overreaction, and it may
> not save much complexity.
It could save a lot of complexity, by not requiring any first-class
support for namespace lookup on arbitrary objects.
>> It makes object property lookup depend on the set of open
>> namespaces, which means obj.property may compile to entirely
>> different code depending on the context,
> Lexical context, no dynamic open-namespaces scope.
Note I said "compile to" so I think this was clear.
>> and it seems likely it will slow down property lookup when multiple
>> namespaces are open but static type info is missing.
> It certainly could, although we think not in implementations under
> way. Opening multiple namespaces without is not free in a dynamic
> Is the name lookup algorithm much simpler if namespaces are top-
> level only? Since obj.prop could end up with obj referring to the
> (or I should write "a") global object, I don't see it. Unless you're
> proposing outlawing such object references using the namespaces open
> at top-level when obj is the global object.
I would propose that unqualified import only affects lexically scoped
lookups, not object property access, even if the object in question is
the global object. In particular, if you are willing to say
"global.property" instead of "property", it is not such a hardship to
>> If the only real justification is that it's a nice generalization,
>> then I do not think it is worth the performance hit.
> The nice generalization followed from particular use-cases, it did
> not precede them. I cited those cases (briefly). How about being
> responsive to them?
I think many (perhaps all) of those cases either use namespaces
gratuitously or work fine without unqualified import (and so could use
namespaces by convention). For example it doesn't seem important to
allow unqualified import of the meta namespace.
>>> ES (any version) has objects as scopes, as well as prototypes.
>>> It's hard to keep the gander -- objects below the top level, or on
>>> the prototype chain -- from wanting the same sauce that the goose
>>> -- the global object -- is trying to hog all to itself.
>> Is it really? Is there any other language where namespacing of the
>> global namespace has led to namespacing at the sub-object level? C+
>> +, Java and Python all get by fine without namespacing of
>> individual object properties.
> C++ and Java are not the right paradigms for JS/ES. Python is
> better, but Python *does* allow import in local scope.
Python allows import from inside a local namespace, but does it allow
import from outside a local namespace to affect lookup into that
namespace? I am not aware of such a feature but I'm not a Python expert.
>> The reason namespacing at top level is essential to programming in
>> the large is that the global namespace is a shared resource and
>> must be partitioned in controlled ways to avoid collision in a
>> large system. But I do not see how this argument applies to classes
>> or objects.
> See Mark's big post, which discusses (in item (b)) extending
> objects, including standard ones.
> Saying the global object is a shared resource that must be
> partitioned, etc., but no others reachable from it, particularly
> class objects, are shared resources, is begging the question: what
> makes any object a shared resource? That the global is the only
> necessarily shared object does not reduce the benefit, or make the
> cost prohibitive, of sharing other objects reachable from it.
The benefit is less, because you can use separate objects in different
namespaces instead of a shared object with namespaces inside it. The
cost is greater because it makes all property lookup more expensive.
>> The fact that the generalization seems to be unique to ES4 makes me
>> dubious of its actual usefulness. If it has a performance cost,
>> then the generalization seems like a dubious choice.
> First, performance is not king or JS would not have prototypes and
> dynamic typing. It's not a trump card.
JS does have many features that are not good for performance. But that
does not mean we should add more.
> Second (after all the warm-up sparring), you didn't respond to the
> particulars that led to the generalization:
> * internal namespace per compilation unit for information hiding --
> hardcode as a special case?
I'm not sure how this applies to unqualified import of namespaces on
arbitrary object properties.
> * iterator and meta hooks in objects. Ugly __get__, etc., names
Unqualified import is not necessary for iterator or meta hooks.
Namespaces by convention (or __decoratedNames__) would be enough.
> * helper_foo() and informative_bar() in the RI?
I don't think any language feature should exist solely for the
convenience of the RI.
> The use of __ brackets is a problem for rewriting systems like Caja.
> Whitelisting standard __hook__ names could work, but is this really
> the best we can do? I doubt it.
>>> Is the cost too high? I think that depends on how the name lookup
>>> algorithm works on real-world code. AS3 developers have data to
>>> share. Let's get into that.
>> I'd love to hear the data. AS3 developers, can unqualified lookup
>> of object properties on untyped references in the presence of
>> property namespaces be as fast as when there aren't namespaces at
>> all? If so, how? The most obvious way to do property lookup when
>> there is no static type info is a hashtable lookup on each
>> prototype chain entry, but I do not see an obvious way that a
>> single hashtable lookup can look in multiple namespaces.
> Competitively optimizing JS, excluding namespaces, increasingly
> requires non-obvious implementation techniques.
For that very reason, it is a very bad idea to add features that
intrinsically require non-obvious implementation techniques to get
decent performance. If more effort must be spent the necessary
complexity of the language just to preserve current levels of
performance, then that takes away resources from implementing
unnecessary complexity to improve performance beyond current levels.
In general, keeping the language simpler is good for performance.
Other things being equal, simpler implementations are easier to
change, and have more room to add complexity for optimization without
becoming too complex for human understanding.
I will agree that some added language features are essential but I
think minor improvements in expressiveness that have large complexity
cost are a poor tradeoff.
> This is a good trade-off if it can be done in reasonable footprint,
> since there is a huge installed base, and a pretty-big knowledge
> base. We're not, for example, going to remove the ability to replace
> String.prototype.charAt, in any compatible ESn version.
Preserving compatibility with existing performance-harming features is
not the same thing as introducing new ones.
> Optimization ease is not and should not be the sole consideration.
> Exotic techniques should not be mandated by the spec, on the other
> hand. But without 'use namespace N' pragmas, programmers will not
> run into ambiguities at compile time, that result in run-time cost.
> Programmers can buy by the yard here, as with other parts of the
> language that trade performance (or alternatively: that fuel demand
> for more optimized runtimes) in exchange for expressiveness. And for
> a lot of JS code, core language performance does not matter even if
> you go nuts with eval and 'with', compared to other costs dominating
> the critical paths.
Programmers have found ways to live with today's performance, and it
is true that for some applications core language performance is not
the bottleneck. But that doesn't mean we can feel free to ignore
performance considerations in the design of new language features.
>> I suspect the answer to this in AS3 is that if you want
>> performance, you have to use type declarations.
> That may be the case for AS3 code using Flex, but even such a result
> would be informative -- don't open multiple namespaces if you're
> using untyped objects and targeting an unoptimized implementation.
> But really, why is any of the several feature combinations that
> could hurt performance (with, eval, deep scope chains and prototype
> chains in most implementations) a reason to cripple the language?
> Performance is not king, and JS ain't C++.
Is removing unqualified import of namespaces at non-global scope (the
only aspect of namespaces that seems prima facie harmful to
performance) really "crippling the language"?
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Es4-discuss