Enumerating standard class properties & methods

The objects Date, String, Number, etc are not enumerable within script.  Not
that that's a newsflash :) but I'm wondering if enumeration could be
included in/has been considered for future releases.  AFAIK there's little
overhead.

Thanks,

Sterling


0
Sterling
12/17/2003 6:09:02 AM
netscape.mozilla.jseng 1530 articles. 0 followers. Follow

16 Replies
261 Views

Similar Articles

[PageSpeed] 53


Sterling Bates wrote:

> The objects Date, String, Number, etc are not enumerable within script.  Not
> that that's a newsflash :) but I'm wondering if enumeration could be
> included in/has been considered for future releases.  

ECMAScript edition 3 in section 15 where the native ECMAScript objects 
are defined says

There are certain built-in objects available whenever an ECMAScript 
program begins execution. One, the
global object, is in the scope chain of the executing program. Others 
are accessible as initial properties of the
global object.

....

Every other property described in this section has the
attribute { DontEnum } (and no others) unless otherwise specified.



And there is nothing specified for the constructor properties Date, 
String, Number that they should be enumerable thus I don't think any 
implementation aiming to be compliant with the ECMAScript specification 
is allowed to enumerate those properties.
-- 

	Martin Honnen
	http://JavaScript.FAQTs.com/

0
Martin
12/17/2003 11:06:39 AM
"Martin Honnen" <Martin.Honnen@t-online.de> wrote in message
news:brpcou$nt1@ripley.netscape.com...
> And there is nothing specified for the constructor properties Date,
> String, Number that they should be enumerable thus I don't think any
> implementation aiming to be compliant with the ECMAScript specification
> is allowed to enumerate those properties.

Just to press the point, though, none of the implementations are strictly
equivalent to the ECMA spec.  While it is particularly specific regarding
the DontEnum attribute, I don't believe it would be a major departure from
the spec to differ on that particular attribute.  Having said that, I'm not
a SpiderMonkey engineer either.

Where it's become an issue in one situation is recursive enumeration.  The
software enumerates to a Date, attempts to enumerate it, only to find it has
no properties or methods.  Having numerous methods, however, it would be
handy to enumerate the object rather than store a static list of methods
available to Date objects in the hosting app.

Thanks,

Sterling


0
Sterling
12/17/2003 5:29:30 PM
Sterling Bates wrote:

> Just to press the point, though, none of the implementations are strictly
> equivalent to the ECMA spec.

What do you mean?

The ECMA-262 Edition 3 spec allows extensions (see Chapter 16), so don't 
count those as "non-standard".

Any deviations from explicit normative ("must", "should") specs are a 
different issue.  Those would be bugs, and we test, track, and fix them. 
   Having no spec is bad; having a spec we extend is good; flouting the 
spec is bad.  There may be a handful of cases where we depart from the 
spec for good, well-considered backward compatibility reasons.  Those 
too are different.

Enumerating objects with for..in was always meant to skip "built-in" or 
"system pre-defined" functions and other properties, enumerating only 
user-defined properties.  That's just the way JS is.  If you need to 
enumerate all properties, you'll have to do something extra.

/be

0
Brendan
12/17/2003 6:51:45 PM
"Brendan Eich" <brendan@meer.net> wrote in message
news:3FE0A5C1.20205@meer.net...
> Sterling Bates wrote:
>
> > Just to press the point, though, none of the implementations are
strictly
> > equivalent to the ECMA spec.
>
> What do you mean?
[...]
> spec is bad.  There may be a handful of cases where we depart from the
> spec for good, well-considered backward compatibility reasons.  Those
> too are different.

I was referring to spec departures in general.  I didn't mean to imply that
there were no reasons for the departures, I just recalled reading about
some.

> Enumerating objects with for..in was always meant to skip "built-in" or
> "system pre-defined" functions and other properties, enumerating only
> user-defined properties.  That's just the way JS is.  If you need to
> enumerate all properties, you'll have to do something extra.

That's cool.  Do you know of a way to obtain the memory address for a given
class declaration (like Date) so I can check it from outside the engine?

Sterling


0
Sterling
12/17/2003 7:10:16 PM
Sterling Bates wrote:

> That's cool.  Do you know of a way to obtain the memory address for a given
> class declaration (like Date) so I can check it from outside the engine?

Why do you need that?  Is this related to enumerating the global object 
to include all [[DontEnum]] properties?

If you really need to know the JSClass* for the Date class, you'll have 
to do something like this:

     JSBool ok;
     static const char date_proto_str[] = "Date.prototype";
     jsval rval;
     JSClass *date_class;

     ok = JS_EvaluateScript(cx, global,
                            date_proto_str, sizeof date_proto_str - 1,
                            NULL, 0,
                            &rval);
     if (!ok)
         fail somehow;

     date_class = JS_GET_CLASS(cx, JSVAL_TO_OBJECT(rval));

If you really need a Date API, there are some functions in jsdate.h that 
are marked JS_FRIEND_API, which means they're not frozen as solid as the 
JS_PUBLIC_API functions prototyped in jsapi.h -- but OTOH they haven't 
changed in years.

If you need other class pointers or APIs, let me know.

/be

0
Brendan
12/17/2003 7:21:06 PM
"Brendan Eich" <brendan@meer.net> wrote in message
news:3FE0ACA2.6040908@meer.net...
> Why do you need that?  Is this related to enumerating the global object
> to include all [[DontEnum]] properties?

Basically, yes.  I'll statically store the methods for each standard class,
then detect the class type at runtime using the code you've provided below.
That way the bridge code can enumerate as deep as users need, and the engine
stays compliant :-)

> If you need other class pointers or APIs, let me know.

Thanks for your help.  Where do you find the time to help us out when you
have huge responsibilities at Mozilla?

Take care,

Sterling


0
Sterling
12/17/2003 7:35:03 PM
Sterling Bates wrote:
> "Brendan Eich" <brendan@meer.net> wrote in message
> news:3FE0ACA2.6040908@meer.net...
> 
>>Why do you need that?  Is this related to enumerating the global object
>>to include all [[DontEnum]] properties?
> 
> 
> Basically, yes.  I'll statically store the methods for each standard class,
> then detect the class type at runtime using the code you've provided below.
> That way the bridge code can enumerate as deep as users need, and the engine
> stays compliant :-)

Why do you need all the special casing?  Why not use 
JS_ResolveStandardClass?

/be

0
Brendan
12/17/2003 7:52:05 PM
"Brendan Eich" <brendan@meer.net> wrote in message
news:3FE0B3E5.2000904@meer.net...
> Sterling Bates wrote:
> >
> > Basically, yes.  I'll statically store the methods for each standard
class,
> > then detect the class type at runtime using the code you've provided
below.
> > That way the bridge code can enumerate as deep as users need, and the
engine
> > stays compliant :-)
>
> Why do you need all the special casing?  Why not use
> JS_ResolveStandardClass?

As I understand it, JS_ResolveStandardClass is used for lazy standard class
initialization.  What I'm trying to do is enumerate the methods of an object
of a standard class type.  The fastest way I know of to determine an
object's class type is comparing the memory locations of the class structs
(that's how SM does it anyway), and from there I can return a list of the
standard class's methods.

Is that correct?

Thanks,

Sterling


0
Sterling
12/17/2003 8:16:21 PM
Sterling Bates wrote:

> As I understand it, JS_ResolveStandardClass is used for lazy standard class
> initialization.  What I'm trying to do is enumerate the methods of an object
> of a standard class type.  The fastest way I know of to determine an
> object's class type is comparing the memory locations of the class structs
> (that's how SM does it anyway), and from there I can return a list of the
> standard class's methods.

Ok, so you have a date object in hand, and want to build the Object 
Pascal bridgework needed to reflect its properties into O.P.?

Why do that eagerly?  Why not do it as each property is accessed (all 
may not be needed)?

/be

0
Brendan
12/17/2003 8:22:18 PM
"Brendan Eich" <brendan@meer.net> wrote in message
news:3FE0BAFA.3000209@meer.net...
> Ok, so you have a date object in hand, and want to build the Object
> Pascal bridgework needed to reflect its properties into O.P.?
>
> Why do that eagerly?  Why not do it as each property is accessed (all
> may not be needed)?

It sounds like that would be used on a wrapper for the Date class.  The
functionality I'm attempting to emulate is a JS_Enumerate call on a
Date-classed object.  Rather than simply calling JS_Enumerate, however, I'll
first determine whether the object's class is standard.  If so, I return the
stored list of functions (I may have to change the list for different js
versions) for that class, otherwise call JS_Enumerate.  The bridge's user
won't need to know the origin, just receive the array of string values.

Sterling


0
Sterling
12/17/2003 8:41:16 PM
Sterling Bates wrote:
>
> It sounds like that would be used on a wrapper for the Date class.  The
> functionality I'm attempting to emulate is a JS_Enumerate call on a
> Date-classed object.  Rather than simply calling JS_Enumerate, however, I'll
> first determine whether the object's class is standard.  If so, I return the
> stored list of functions (I may have to change the list for different js
> versions) for that class, otherwise call JS_Enumerate.  The bridge's user
> won't need to know the origin, just receive the array of string values.

So, you'll hardcode all the properties of standard classes and their 
prototypes?

Why do this?  JS does not.  Its reflection via your bridge in O.P. 
shouldn't either, IMO.

/be

0
Brendan
12/17/2003 8:42:21 PM
"Brendan Eich" <brendan@meer.net> wrote in message
news:3FE0BFAD.9020100@meer.net...
> So, you'll hardcode all the properties of standard classes and their
> prototypes?
>
> Why do this?  JS does not.  Its reflection via your bridge in O.P.
> shouldn't either, IMO.

I agree that hardcoding is not always a good thing, but ruling it out brings
me back to square one.  I'm not aware of another option to dynamically
discover the properties and methods of standard classes.

Sterling


0
Sterling
12/17/2003 8:51:23 PM
Sterling Bates wrote:

> "Brendan Eich" <brendan@meer.net> wrote in message
> news:3FE0BFAD.9020100@meer.net...
> 
>>So, you'll hardcode all the properties of standard classes and their
>>prototypes?
>>
>>Why do this?  JS does not.  Its reflection via your bridge in O.P.
>>shouldn't either, IMO.
> 
> 
> I agree that hardcoding is not always a good thing, but ruling it out brings
> me back to square one.  I'm not aware of another option to dynamically
> discover the properties and methods of standard classes.

If you don't need to enumerate them (JS does not), then why do you not 
simply look up any name on demand, and find whether it refers to a 
property of the global object (etc. down the object "tree" or graph)?

/be

0
Brendan
12/17/2003 8:54:39 PM
"Brendan Eich" <brendan@meer.net> wrote in message
news:3FE0C28F.7060300@meer.net...
> Sterling Bates wrote:
>
> > I agree that hardcoding is not always a good thing, but ruling it out
brings
> > me back to square one.  I'm not aware of another option to dynamically
> > discover the properties and methods of standard classes.
>
> If you don't need to enumerate them (JS does not), then why do you not
> simply look up any name on demand, and find whether it refers to a
> property of the global object (etc. down the object "tree" or graph)?

I don't actually need the list of methods for the bridge code to work, I
need it so that clients of the bridge will get a list of methods of all
objects when they call Enumerate on them.  Maybe it's easier to show the
code.  A TJSObject is a wrapper for any JSVAL_OBJECT (written here from
memory...):

    TJSObject = class
    private
        JSObj: PJSObject;
    public
        [...]
        function Enumerate: TStringArray;
        procedure GetProperty(const Name: String; var retval: TJSObject);
        [...]
    end;

    function TJSObject.Enumerate: TStringArray;
    var
        jslist: JSIdArray;
    begin
        jslist := JS_Enumerate(self.JSObj);
        [... parse into Delphi string array ...]
    end;

    procedure TJSObject.GetProperty(const Name: String; var retval:
TJSObject);
    var
        rval: jsval;
        jsobj: PJSObject;
        prv: Pointer;
    begin
        JS_GetProperty(Context, JSObj, PChar(Name), @rval);
        jsobj := JSValToObject(rval);
        prv := JS_GetPrivate(Context, jsobj);

        if (prv = nil) then
            retval := TJSObject.Create(JSEngine, jsobj)
        else
            retval := TJSObject(prv);
    end;

First the user calls Enumerate for the currently wrapped jsobject (say
global).  When the user gets to an item of type Object (determined
elsewhere), it calls the above GetProperty method, which wraps the property
of that name in another TJSObject, or reuses the current wrapper for that
property.  It's like reconstructing the object tree, as necessary, in
Delphi.

When a TJSObject is wrapping a Date-classed object, the .Enumerate call will
return an empty array.  The ideal is to return a list of methods, since
that's what the client expects.  That's where I'm pondering the hardcoded
list of properties.

Sterling


0
Sterling
12/17/2003 9:36:13 PM
Sterling Bates wrote:

[bridge description deleted, that's all fine and akin to existing 
bridges, AFAICT.  /be]

> When a TJSObject is wrapping a Date-classed object, the .Enumerate call will
> return an empty array.  The ideal is to return a list of methods, since
> that's what the client expects.  That's where I'm pondering the hardcoded
> list of properties.


That's where you could return an empty array and be conformant with 
ECMA-262 Editions 1-3.  Why do more?

/be

0
Brendan
12/17/2003 9:55:34 PM
"Brendan Eich" <brendan@meer.net> wrote in message
news:3FE0D0D6.4010409@meer.net...
> That's where you could return an empty array and be conformant with
> ECMA-262 Editions 1-3.  Why do more?

Well, 33% of my current userbase (*cough*1 user*cough*) will need to know
what those methods are.  Being as accomodating as I can (it benefits me as
much as everyone else) I can do one of two things:

1. Provide a ClassType method which returns an enumerated value for Date,
Number, Array, etc.
2. Return the list of methods as a transparent operation to the client of
the bridge.

Personally I prefer #2.  I'd rather not force all clients to hardcode the
method lists individually, when it can be done centrally.  OTOH, with #1 I
can claim some level of conformance with the spec -- probably safer long
term.  Depends on whether I'm a non-conformist :)

Thanks Brendan,

Sterling


0
Sterling
12/17/2003 10:16:13 PM
Reply: