Picking property by attribute

Yuh-Ruey Chen maian330 at gmail.com
Mon Aug 18 09:28:00 PDT 2008


OK, with the advent of ES-Harmony, I have no clue whether the language
will support iterators (and maybe generators) or catch-all methods. I
know that namespaces are out.

But assuming a pre-ES-Harmony mindset:

My solution does have bugs: I forgot to filter the results of
iter.next() in the next() method, and I forgot to handle the non-method
case in the get catch-all. So it's supposed to only enumerate over
properties that the object really owns. So it should replicate exactly
what you want. The fixed (pseudo) code:

// Defined in some library (possibly builtin)
class OwnPropertiesEnumerator {
    val obj;
    val iter;
    OwnPropertiesEnumerator(obj) {
        this.obj = obj;
        this.iter = obj.iterator::get();
    }
    public function next() {
        var x = meta::get(iter.next());
        while (x == undefined) {
            x = meta::get(iter.next());
        }
        return x;
    }
    meta function get(name) {
        if (obj.hasOwnProperty(name)) {
            if (obj[name] is Function) {
                // make sure |this| in a method doesn't refer to an
instance of this class
                return function(...args) {
                    if (this is OwnPropertiesEnumerator)
                        return obj[name].apply(obj, args);
                    return obj[name].apply(this, args);
                }
            } else {
                return obj[name];
            }
        }
    }
    meta function set(name, value) {
        obj[name] = value;
    }
    meta function has(name) {
        return obj.hasOwnProperty(name);
    }
    meta function delete(name) {
        if (obj.hasOwnProperty(name))
            delete obj[name];
    }
}
Object.prototype.own = function() {
    return new OwnPropertiesEnumerator(this);
}
Object.prototype.propertyIsEnumerable("own", false);

...

// User code
print(foo.own().bar);
print(foo.own().toString);   // prints undefined
for (var prop in foo.own())   // does not enumerate toString and co.
    print(prop + ": " + foo[prop]);

Ingvar von Schoultz wrote:
> YR Chen wrote:
> > But the syntax you propose is redundant, since you can define a own() 
> > method returning an iterator (for for...in) and a getOwn() method to do 
> > the same thing.
>
> What people wanted so hotly was an object completely unpolluted
> by inheritance from Object. It should have no .toString() etc.
> Your solution does inherit material from Object (and Function).
>
> Therefore the important thing is that obj[*own] is unpolluted.
> And yet it can inherit anything you want, and this inherited
> material is accessible unambiguously through obj[*!own].
>
> Ingvar
>
>
>
> YR Chen wrote:
> > (Oops, forgot to reply all, so repost)
> > 
> > But the syntax you propose is redundant, since you can define a own() 
> > method returning an iterator (for for...in) and a getOwn() method to do 
> > the same thing. Or, if you think getOwn() is ugly, you can customize the 
> > own() method to also return a "view" object:
> > 
> > // Defined in some library (possibly builtin)
> > class OwnPropertiesEnumerator {
> >     val obj;
> >     val iter;
> >     OwnPropertiesEnumerator(obj) {
> >         this.obj = obj;
> >         this.iter = obj.iterator::get();
> >     }
> >     function next() {
> >         return iter.next();
> >     }
> >     meta function get(name) {
> >         if (obj.hasOwnProperty(name))
> >             if (obj[name] is Function) {
> >                 // make sure |this| in a method doesn't refer to an 
> > instance of this class
> >                 return function(...args) {
> >                     if (this is OwnPropertiesEnumerator)
> >                         return obj[name].apply(this.obj, args);
> >                     return obj[name].apply(this, args);
> >                 }
> >             }
> >             return obj[name];
> >     }
> >     meta function set(name, value) {
> >         obj[name] = value;
> >     }
> >     meta function has(name) {
> >         return obj.hasOwnProperty(name);
> >     }
> >     meta function delete(name) {
> >         if (obj.hasOwnProperty(name))
> >             delete obj[name];
> >     }
> > }
> > Object.prototype.own = function() {
> >     return new OwnPropertiesEnumerator(this);
> > }
> > Object.prototype.
> > propertyIsEnumerable("own", false);
> > 
> > ...
> > 
> > // User code
> > print(foo.own().bar);
> > for (var prop in foo.own())
> >     print(prop + ": " + foo[prop]);
> > 
> > Or something like that. I'm not completely familiar with ES4 syntax and 
> > what has changed in the past months (using the Oct 07 overview pdf as a 
> > reference), so the above may not be strictly correct, but you should get 
> > the intent :)
> > 
> > -Yuh-Ruey Chen
> > 
> > 
> > On Sun, Aug 10, 2008 at 5:52 PM, Ingvar von Schoultz 
> > <ingvar-v-s at comhem.se <mailto:ingvar-v-s at comhem.se>> wrote:
> > 
> >     YR Chen wrote:
> > 
> >         There's no separate "namespace" for enumerable properties.
> > 
> > 
> >     This is about something else, something that's come up several
> >     times in the discussion archives. See for example this post:
> >     https://mail.mozilla.org/pipermail/es4-discuss/2007-March/000578.html
> > 
> > 
> >         Also, let's not add syntax for things that can easily be done
> >         with functions.
> > 
> > 
> >     Several syntaxes have been discussed. It seems to me that this
> >     syntax would solve several problems that were discussed, and is
> >     simple in implementation, very flexible and nicely readable.
> > 
> >     Whether people still feel a need for a syntax, I don't know.
> > 
> >     Ingvar
> > 
> > 
> > 
> >     YR Chen wrote:
> > 
> >         There's no separate "namespace" for enumerable properties. They
> >         are properties with a hidden enumerable flag set. With that
> >         said, in ES4, only non-fixed properties in the public namespace
> >         will be enumerable by default. That means that properties
> >         defined in classes will not be enumerable unless prefixed with
> >         |prototype|, and only "custom" properties defined in the public
> >         namespace (which is the default namespace) are enumerable. So if
> >         you don't want a property to be enumerable, just define it in
> >         another namespace and also open that namespace (via |use
> >         namespace|). Or you can toggle the enumerable flag off via some
> >         new method whose name escapes me.
> > 
> >         Also, let's not add syntax for things that can easily be done
> >         with functions. You can create your own iterator functions and
> >         use them, e.g.:
> > 
> >         // assuming pythonic generators are in ES4 (there's an
> >         equivalent, albeit uglier, non-generator way)
> >         myDictClass.prototype.own = function() {
> >            for (var x in this.iterator::get()) {
> >                if (this.hasOwnProperty(x))
> >                    yield x;
> >            }
> >         }
> > 
> >         for (var x in myDict.own()) ...
> > 
> >         -Yuh-Ruey Chen
> > 
> >         On Fri, Aug 8, 2008 at 1:07 PM, Ingvar von Schoultz
> >         <ingvar-v-s at comhem.se <mailto:ingvar-v-s at comhem.se>
> >         <mailto:ingvar-v-s at comhem.se <mailto:ingvar-v-s at comhem.se>>> wrote:
> > 
> >            I think this would be useful:
> > 
> >            Get an enumerable property:
> > 
> >                var x = myDict [*enumerable] .someName;
> > 
> >                var x = myDict [*enumerable] [someVariable];
> > 
> >            Call the non-enumerable .toString():
> > 
> >                var x = myDict [*!enumerable] .toString();
> > 
> >            Distinguish between owned and inherited properties:
> > 
> >                var x = myDict [*own] .someName;
> > 
> >                var x = myDict [*!own] .toString();
> > 
> >            Loop through a subset:
> > 
> >                for (var x in myDict [*own]) {...}
> > 
> >            The syntax is meant to suggest that we pick a subset, such as
> >            all the enumerable properties, and then pick a property from
> >            this subset.
> > 
> >            Here's an alternate syntax, more logical but less readable
> >            in my opinion:
> > 
> >                var x = myDict .:enumerable .someName;
> > 
> >                var x = myDict .!enumerable .toString();
> > 
> >            --
> >            Ingvar von Schoultz
> > 
> >            _______________________________________________
> >            Es4-discuss mailing list
> >            Es4-discuss at mozilla.org <mailto:Es4-discuss at mozilla.org>
> >         <mailto:Es4-discuss at mozilla.org <mailto:Es4-discuss at mozilla.org>>
> > 
> >            https://mail.mozilla.org/listinfo/es4-discuss
> > 
> > 
> > 
> > 
> >     -- 
> >     Ingvar von Schoultz
> > 
> >     ------- (My unusual use of capitals in code comes from my opinion that
> >     reserved and predefined words should all start with lowercase, and
> >     user-defined should all start with uppercase, because this will easily
> >     and elegantly prevent a host of name-collision problems when things
> >     like programming languages are upgraded with new labels.)
>
>   


More information about the Es-discuss mailing list