Namespaces as Sugar (was: complexity tax)
Brendan Eich
brendan at mozilla.org
Tue May 27 11:00:09 PDT 2008
On May 27, 2008, at 8:45 AM, Maciej Stachowiak wrote:
> I don't see how any of this argues for namespacing of properties on
> non-global objects, or why that case in particular requires
> unqualified import.
The topic was any single object, so if these are good for the global
object, they may (not must) be good for other objects. That's the
general (uniformity) argument, made further below (I'm hoping for a
response).
>>> One can certainly question the need for any namespacing of object
>>> properties, let alone unqualified import of namespaces for such
>>> purposes.
>>
>> I hope so. I'd rather have someone question unqualified import
>> than implicitly dismiss it, which is what seems to be happening.
>
> I don't see how your statement is responsive.
Hey, I was agreeing with you (Mr. Assistant District Attorney Sir :-
P). Questioning is fine.
What was "responsive" about your non-sequitur "One can certainly
question the need ..." anyway? No one objects to asking clear
questions that are not of the "when did you stop beating your wife"
kind.
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.
> Namespacing of non-object properties is poorly justified, in my
> opinion. Unqualified import of top-level names is well-justified. I
> don't see why you keep mixing the two together.
Sure you do, below where I gave particulars that led to the
generalized namespace scheme in ES4.
>>> but does not mean namespaces need to generalize beyond the global
>>> scope. For example, global unqualified namespace import could
>>> desugar
>>> (logically) into the injection of scope chain items instead of
>>> into a
>>> general property lookup mechanism.
>>
>> 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 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.
> 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
language.
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.
> 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?
>> 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.
> 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.
Prototype (the Ajax library) may have erred in extending standard
object prototypes. But if it had namespaces as proposed in ES4, and
control over enumerability, then why not? Then there are non-
prototype standard objects that can be (and are, in JS1/ES3 code
today) shared and extended, with possibly conflicting names.
Anyway, it seems we're beating around the bush still. Responding to
the particular reasons for generalized namespaces would be better
than asserting that the global object is the only shared resource,
simply because it must be shared.
>> Objects and their properties move around over time, both along the
>> scope and prototype chains. Real web apps I've studied from a low-
>> level actually take advantage of the ability to "pun" objects
>> along both chains (including the global object).
>
> Nontheless, the global namespace is unique. There's no way to
> replace the global object.
You're right, but that does not mean programmers should have to
partition only the global object with namespaces or anything like
them. The global object is the first object to come to mind, but not
the only, and Prototype along with lots of other (library or ad-hoc)
JS code on the web shows the utility of extending non-global objects.
I do not mean to oversell this point, since Ajax hackers have swerved
away from Prototype-like extension. But that swerving is focused on
standard prototypes, especially Object.prototype, and it depends also
on the inability to prevent for-in enumeration. It is not reason for
confining namespacing to the global object, any more than Prototype
is proof that we *must* allow namespacing at any level in the object
hierarchy.
The arguments so far are not going to make or break namespaces as
proposed, by themselves. Moving along:
>> Also, JS hackers often prototype in global code and then push
>> things down into closures or sub-objects.
>>
>> Then there is the namespaces-for-versioning idea, which wants to
>> cut across classes as well as global objects.
>>
>> I'm not going to belabor the general argument for uniformity that
>> favors namespaces as qualifiers usable in all objects that can
>> reach the given namespace by reference (if it's opaque) or use it
>> by name (if transparent), because it is a generalization. We have
>> many and specific use-cases in ES4 (intrinsic, iterator, helper,
>> informative come to mind) for sub-global namespacing. We've
>> generalized, instead of making ad-hoc or particular and
>> restrictive solutions.
>
> 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.
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?
* iterator and meta hooks in objects. Ugly __get__, etc., names instead?
* helper_foo() and informative_bar() in 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.
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.
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.
> 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++.
/be
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.mozilla.org/pipermail/es-discuss/attachments/20080527/2a65a4d1/attachment-0002.html
More information about the Es4-discuss
mailing list