extracting namespace from a property

Yuh-Ruey Chen maian330 at gmail.com
Tue Feb 27 21:28:30 PST 2007


Brendan Eich wrote:
> > There are some use cases for processing keys,
> > namely calling some string method on a key or passing a key to a
> > function expecting a string, and any code doing that is likely  
> > going to
> > break the moment a qualified property is added to an object. Consider:
> >
> > for (k in o) {
> >     var prefix = k.substr(0, k.indexOf(':'));
>
> Such code is already broken by E4X, which extended the type of  
> property identifier to be a union with another arm (QName) already.  
> But perhaps E4X's spec authors made a mistake. Ok, moving on:
>
> > which might be used if an author decided to use pseudo-namespaces
> > (remember this is ES3 code). Both substr and indexOf are String  
> > methods,
> > so it will only work if k is a string (either primitive or object)  
> > or is
> > structurally compatible with String (at least with respect to substr()
> > and indexOf() in this example). The proposed Name class doesn't  
> > have any
> > of these methods, so the above code would cause an error. This is only
> > one type of case, but I'm sure there are other use cases where a  
> > string
> > method is called on a key.
>
> Igor suggested something similar in his last message: make String and  
> Name both compatible with a structural type. But we can't make String  
> <: {qualifier: Namespace, identifier: String} without polluting  
> String with 'qualifier' and 'identifier' properties. That seems as  
> bad, aesthetically, as anything you are trying to fix, although  
> operationally it might not break real-world code.
>   

Yeah, that was going to be my first suggestion - adding qualifier and
identifier to String as a hack.

But that does give me an alternative and much simpler idea: Overload the
Name constructor and function to accept a single parameter, such that
Name(k) == Name(null, k). This would allow code like this:

for (k in o)
    print(Name(k).identifier);

No need for a switch type statement, although that would probably be
more efficient.

> > Define a new type of primitive - I'll call it UnqualifiedKey. It is
> > basically a string. The only difference is how it is handled when it's
> > converted to an object. When an UnqualifiedKey primitive is  
> > converted to
> > an object (typically as a temporary object that methods can act upon),
> > the new Name(null, key) is returned. In terms of efficiency, this  
> > isn't
> > much worse than what happens right now (temporary String objects being
> > created).
>
> Adding primitives is the wrong way to go. It spreads complexity  
> around the built-in types' conversion methods, instead of leaving the  
> hassle for the (few, I claim) for-in loop writers who expect a string  
> id.
>
> BTW, primitives are a problem still -- we had hoped to unify string  
> and String, boolean and Boolean, etc. (number types are different,  
> due to int uint double decimal being the "primitives" while Number is  
> the old wrapper class in ES1-3).  Unification is looking too  
> incompatible, so we are trying to unify as much as possible and keep  
> compatibility. But more on that in a separate message.
>
> > Furthermore, Name will somehow contain all the String methods and
> > properties, so that Name.stringprop is equivalent to
> > Name.toString().stringprop.
>
> Now that's a good idea, and it makes your counterexample above  
> (k.substr) work. I will make Name <: String in the name objects  
> proposal.
>   

Well as I mentioned, although Name would derive from String, it would
still have to redefine all of String's methods. This implies that any
method added to String's prototype would not automatically work with a
Name instance. Unless the way Name delegates String methods via some
__noSuchMethod__/__resolve__ hook.

> > (1) There's probably some existing code out there like this:
> >
> > function foo(s) {
> >     if (typeof s == "string" || s instanceof String) {
> >        // do something
> >     }
> >     else if (typeof s == "number" || s instanceof Number) {
> >        // do something
> >     }
> >     // etc.
> > }
> > for (k in obj)
> >     foo(s);
> >
> > so typeof(k) should always be "string" and Object(k) instanceof String
> > should always be true, regardless of whether s represents a qualified
> > identifier or not.
>
> Given Name <: String, it makes sense for (typeof n === "string")  
> given (n is Name).
>   

Does this mean that in ES4 typeof Object(string) == "string" instead of
"object" (and for other primitive wrappers)? Since Name instances are
objects, typeof name should be "object", unless objects and their
primitive counterparts have been unified with respect to typeof.

> I do not propose to add more primitive types. OK?
>   

I imagine those primitive types to be more of a language implementation
construct, since they're basically strings and Names with special flags
that determine how they're treated in the ToObject conversion.

Well whatever the case, I'd be satisfied with the solution I proposed above.

> Thanks for keeping this conversation going.
>
> /be
>   

My pleasure :)

-Yuh-Ruey



More information about the Es4-discuss mailing list