extracting namespace from a property

Brendan Eich brendan at mozilla.org
Tue Feb 27 15:44:05 PST 2007

On Feb 28, 2007, at 12:26 AM, Yuh-Ruey Chen wrote:

> Brendan Eich wrote:
>>> Although this helps, it would still be a hassle to have to check
>>> whether
>>> an enumerated property n is a Name or String. I can't do
>>> n.identifier if
>>> n is a String.
>> You have to use 'switch type' or equivalent.
> That's hardly ideal.

Backward compatibility is that way, sometimes. But it trumps  
incompatible idealism. :-/

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

> 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  

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  

> (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).

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

Thanks for keeping this conversation going.


More information about the Es4-discuss mailing list