isPropertyEnumerable is going to stay broken?

# Garrett Smith (18 years ago)

bugzilla.mozilla.org/show_bug.cgi?id=57048

In this bug, dated 2000, Brendan and David agreed that isPropertyEnumerable should check the prototype chain.

It should not backwards compatibility, but such functionality in the language seems necessary. How to check enumerable attribute, including the prototype chain?

spec:chapter_19_native_objects#object_objects

Garrett

# Garrett Smith (18 years ago)

sorry, propertyIsEnumerable.

# Brendan Eich (18 years ago)

On Sep 8, 2007, at 10:06 PM, Garrett Smith wrote:

bugzilla.mozilla.org/show_bug.cgi?id=57048

In this bug, dated 2000, Brendan and David agreed that isPropertyEnumerable should check the prototype chain.

That was a long time ago, and while David Flanagan carries a lot of
weight with many folks, he was not on ECMA TC39 TG1, and no one on
the group changed the spec.

A lot of water under the bridge since then.

It should not backwards compatibility,

Famous last words. :-)

We try to spider the web (Alexa top 1000 and the like) looking for
counterexamples to such claims, and if we fail to find any, or
better, we find instances of confusion where the incompatible fix is
assumed (i.e., the JS author thought the spec worked the way we want
to change it to work), then we have some confidence, but not much
more, in favor of making an incompatible change. In general. In this
case, no one has done such a scan. I'll see if I can get one started.

but such functionality in the language seems necessary. How to check enumerable attribute, including the prototype chain?

Either reflect the proto (read-only, please) property as some
implementations do, or hardcode the prototype structure and code your
propertyIsEnumerable tests accordingly.

# liorean (18 years ago)

On Sep 8, 2007, at 10:06 PM, Garrett Smith wrote:

but such functionality in the language seems necessary. How to check enumerable attribute, including the prototype chain?

On 10/09/2007, Brendan Eich <brendan at mozilla.org> wrote:

Either reflect the proto (read-only, please) property as some implementations do, or hardcode the prototype structure and code your propertyIsEnumerable tests accordingly.

Would it be possible to add an optional boolean parameter for searching including the whole prototype chain, so that we get a mechanism to do this that doesn't depend on implementation specifics or code structure?

# Brendan Eich (18 years ago)

On Sep 10, 2007, at 1:21 PM, liorean wrote:

On 10/09/2007, Brendan Eich <brendan at mozilla.org> wrote:

Either reflect the proto (read-only, please) property as some implementations do, or hardcode the prototype structure and code your propertyIsEnumerable tests accordingly.

Would it be possible to add an optional boolean parameter for searching including the whole prototype chain, so that we get a mechanism to do this that doesn't depend on implementation specifics

The alternative above would standardize read-only proto, which
would make that property no longer implementation-specific. But of
course we have no proposal to do that.

or code structure?

Adding another optional argument to propertyIsEnumerable is ugly,
since ES4 has a long-standing proposal to add an optional boolean
parameter for changing enumerability. Two trailing optional
parameters, without named parameters, poses usability (both when
writing code and reading it) hazards. Over-engineering with one
optional object parameter, supporting "keyword" properties, seems bad
too -- we want propertyIsEnumerable to remain simple, with few
arguments in toto.

Is the ES3 behavior a true usability problem in the field, or more of
a discordant spec glitch that we can live with?

# Garrett Smith (18 years ago)

On 9/10/07, Brendan Eich <brendan at mozilla.org> wrote:

On Sep 10, 2007, at 1:28 PM, Garrett Smith wrote:

It's possible to crawl the prototype chain, true. I did not know some implementations crawl the proto for propertyIsEnumerable. Which ones do this?

None that I know of. That bug is old and SpiderMonkey was fixed way back then to follow ES3.

hasOwnProperty does not check the prototype chain

That is what its name implies. That's necessary.

propertyIsEnumerable does not check the prototype chain propertyIsEnumerable returns all enumerable properties in an object instance

You must mean "returns true for" in the last sentence above. I would say "obj.propertyIsEnumerable(id) returns true if id names a direct (own) enumerable property of obj".

yes: propertyIsEnumerable returns true for all enumerable properties in an object

And my point was that it appears to duplicate functionality of hasOwnProperty in a differently named method. The fact that the method was called propertyIsEnumerable instead of isPropertyEnumerable is not great, but the way propertyIsEnumerable is designed is confusing to developers.

propertyIsEnumerable and hasOwnProperty are interchangeable (in conforming hosts, not JScript)

All programmer defined values are enumerable (ES3)

A conforming implementation of ES3 should see no difference between propertyIsEnumerable and hasOwnProperty.

But if we change propertyIsEnumerable to look up the prototype chain, and if a programmer defines a property on a prototype object, then the behavior of code that calls propertyIsEnumerable changes incompatibly -- it could break that programmer's code.

A useful and important feature.

@liorean -- time-warp reading your message...

It looks like you replied only to me -- or did you reply-all and I'm missing headers on your message?

Ug. I'm retarded :P

Sorry

Garrett

# Brendan Eich (18 years ago)

On Sep 10, 2007, at 2:21 PM, Garrett Smith wrote:

And my point was that it appears to duplicate functionality of hasOwnProperty in a differently named method.

The two functions are different:

js> var Op = Object.prototype;

js> Op.foo = 42;

42 js> print(Op.hasOwnProperty('foo'), Op.propertyIsEnumerable('foo'));

true true js> print(Op.hasOwnProperty('toString'), Op.propertyIsEnumerable ('toString')); true false

The fact that the method was called propertyIsEnumerable instead of isPropertyEnumerable is not great, but the way propertyIsEnumerable is designed is confusing to developers.

I've never heard that complaint directly, or in a
bugzilla.mozilla.org report. Can you cite complaints anywhere on the
web? I believe you, but it would be good to have evidence.

propertyIsEnumerable and hasOwnProperty are interchangeable (in conforming hosts, not JScript)

This statement is false.

# Neil Mix (18 years ago)

I think this is what Garrett is referring to:

js> function f() {}

js> f.prototype.foo = "blah";

blah js> var x = new f();

js> print(x.propertyIsEnumerable("foo"));

false js> for (var n in x) print(n);

foo

And I have to agree with him, the method is confusing. Based on its
name, I'd expect it to return true if the property can be enumerated
via for-in loop on the given object, regardless of where the property
exists in the prototype chain.

# Garrett Smith (18 years ago)

On 9/10/07, Brendan Eich <brendan at mozilla.org> wrote:

On Sep 10, 2007, at 2:21 PM, Garrett Smith wrote:

And my point was that it appears to duplicate functionality of hasOwnProperty in a differently named method.

The two functions are different:

js> var Op = Object.prototype; js> Op.foo = 42; 42 js> print(Op.hasOwnProperty('foo'), Op.propertyIsEnumerable('foo')); true true js> print(Op.hasOwnProperty('toString'), Op.propertyIsEnumerable ('toString')); true false

The fact that the method was called propertyIsEnumerable instead of isPropertyEnumerable is not great, but the way propertyIsEnumerable is designed is confusing to developers.

I've never heard that complaint directly, or in a bugzilla.mozilla.org report. Can you cite complaints anywhere on the web? I believe you, but it would be good to have evidence.

propertyIsEnumerable and hasOwnProperty are interchangeable (in conforming hosts, not JScript)

This statement is false.

You're example clarifies that. I see how it could be useful, in fact, for examining a prototype chain to filter out extra stuff that got shoved in.

For user-defined objects, propertyIsEnumerable and hasOwnProperty are interchangeable.

var obj = { Garrett : "monkeybrains" ,borked : "javascript" // transitivity fixed :-) ,toString : function() { return "an enumerable prop"; } ,valueOf : function() { return 2; } // also enumerable. };

Is there a value for s where the following is true: (obj.hasOwnProperty( s ) != obj.propertyIsEnumerable( s ))

Garrett

# Brendan Eich (18 years ago)

On Sep 10, 2007, at 2:41 PM, Neil Mix wrote:

I think this is what Garrett is referring to:

js> function f() {} js> f.prototype.foo = "blah"; blah js> var x = new f(); js> print(x.propertyIsEnumerable("foo")); false js> for (var n in x) print(n); foo

And I have to agree with him, the method is confusing.

Sure, but that ship sailed (bugzilla.mozilla.org/show_bug.cgi? id=57048#c4).

Based on its name, I'd expect it to return true if the property can be enumerated via for-in loop on the given object, regardless of where the property exists in the prototype chain.

My question remains: is this an incompatible change that will help
more than it hurts, and otherwise be worth making?

Even with the change, hasOwnProperty and propertyIsEnumerable are
different, but from Garrett's latest mail it's clear that we agree
they're functionally the same for most user-defined properties in
their directly-owning objects.

Enumerability is a weak concept. I wish I'd left it out back in 1995,
when I was over-minimizing elsewhere.

# Neil Mix (18 years ago)

And I have to agree with him, the method is confusing.

Sure, but that ship sailed (bugzilla.mozilla.org/show_bug.cgi? id=57048#c4).

I was responding to the following interchange: Garrett: ...but the way propertyIsEnumerable is designed is confusing
to developers. Brendan: I've never heard that complaint directly, or in a
bugzilla.mozilla.org report. Can you cite complaints anywhere on the
web? I believe you, but it would be good to have evidence.

My opinion of the propertyIsEnumerable method was derived from
personal experience, prior to this discussion. Purely FWIW, if that
counts as "evidence."

My question remains: is this an incompatible change that will help more than it hurts, and otherwise be worth making?

If we were voting, I'd vote "yes." If you're asking for objectivity,
I think your crawlers provide the only reliable data. (Searching for
"propertyIsEnumerable filetype:js" on Google yields no hits.)

# Bob Clary (18 years ago)

Neil Mix wrote:

If we were voting, I'd vote "yes." If you're asking for objectivity,
I think your crawlers provide the only reliable data. (Searching for
"propertyIsEnumerable filetype:js" on Google yields no hits.)

Ok. I'll kick off a scan looking for instances of propertyisEnumerable. While I am at it, are there any other constructs people are interested in that I can bundle with this run?

bc

# Garrett Smith (18 years ago)

(fwd to list)... On 9/10/07, Brendan Eich <brendan at mozilla.org> wrote:

On Sep 10, 2007, at 2:41 PM, Neil Mix wrote:

I think this is what Garrett is referring to:

js> function f() {} js> f.prototype.foo = "blah"; blah js> var x = new f(); js> print(x.propertyIsEnumerable("foo")); false js> for (var n in x) print(n); foo

And I have to agree with him, the method is confusing.

Sure, but that ship sailed (bugzilla.mozilla.org/show_bug.cgi? id=57048#c4).

Based on its name, I'd expect it to return true if the property can be enumerated via for-in loop on the given object, regardless of where the property exists in the prototype chain.

My question remains: is this an incompatible change that will help more than it hurts, and otherwise be worth making?

Probably have more important things in the language.

I read that bug rep't and you stated in the last comment "I still think ECMA is wrong, and should be fixed."

I'm considering your question.

I would like it to be fixed, but can't say if it's the Right Thing. I'll consider brining it up on c.l.j

I'm going to make a blog entry about it, too.

Garrett

# Bob Clary (18 years ago)

In a fairly limited scan totaling about 3000 pages of the homepages of 33 top sites including those pages linked from the homepages I found three occurrences of essentially the same script:

kaden.yahoo.co.jp/js/connection/connection-min.js, cn.yimg.com/i/js/ycnconn.js, cn.yimg.com/ncp/fashion/js3/ycnconn.js

where propertyIsEnumerable is used incorrectly (as a property rather than as a function) but which appears to have intended to get the "don't search prototype" behavior.

Due to the nature of the scan (using the narcissus parser in the browser), the scan was fairly slow. I can use a different approach and cover more pages if there is more interest. If not, I'll let this rest here.

# Garrett Smith (18 years ago)

YUI Connection Manager

           for(var prop in this._http_header){
                   if(this._http_header.propertyIsEnumerable){
                           o.conn.setRequestHeader(prop,

this._http_header[prop]); } }

The conditional check will have the effect of filtering out all browsers which don't support propertyIsEnumerable (effectively breaking Safari 2).

Regardless, the proposed change to propertyIsEnumerable will have no effect on the Connection Manager.

There is something called Moodle that seems to use propertyIsEnumerable.

propertyIsEnumerable is a seldom used method.

Have to let implementations know to change support of this feature (if the change happens). Flash, all browsers, Apple (konfabulator, OS), Nokia, et c.

The change might even be widely supported until 2012 for a programmer to use, and then programmers will have to test not for propertyIsEnumerable, but for which one.

if( "propertyIsEnumerable" in Object.prototype ) { // Which propertyIsEnumerable do we have? if( isPropertyIsEnumearablePrototypeEnabled() ) { if( obj.propertyIsEnumerable( prop ) ) {

  }

} }

var isPropertyIsEnumearablePrototypeEnabled = function() { var o = function(){}; var garbage = "~~~__0*"; o.prototype[ garbage ] = true; var supported = o.propertyIsEnumerable( garbage ); return supported; }

Garrett

# Garrett Smith (18 years ago)

On 9/10/07, Brendan Eich <brendan at mozilla.org> wrote:

On Sep 10, 2007, at 2:21 PM, Garrett Smith wrote:

The fact that the method was called propertyIsEnumerable instead of isPropertyEnumerable is not great, but the way propertyIsEnumerable is designed is confusing to developers.

I've never heard that complaint directly, or in a bugzilla.mozilla.org report. Can you cite complaints anywhere on the web? I believe you, but it would be good to have evidence.

Web search: livedocs.adobe.com/flashlite/2/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000728.html, www.adobe.com/livedocs/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00002578.html

Apparently flash actually has a custom "isPropertyEnumerable" method. It's on Adobe's website. I don't do Flash, so I can't say much about it. It looks like a straight rename method, though.

This guy wants a rename, too: lists.macosforge.org/pipermail/webkit-reviews/2005-December/002269.html

isPropertyEnumerable and/or propertyIsEnumerable could return true if an object can be enumerated in a for-in loop, and check the prototype chain.

Given the above change, the old (current) behavior could be achieved with: r.propertyIsEnumerable( p ) && r.hasOwnProperty( p );

The change would allow for 4 different possibilities of r[ p ]

Garrett