Forums

Posting in these forums is disabled. These forums will be available for archive purposes. Please join the new forums at the links below:

  • yui-support - replaces the `YUI 3.x` and `YUI 3 Gallery` forums.
    We have created the following discussion categories within this group to aid discoverability for these most-used topics:
    • Charts for YUI Charts support.
    • DataTable for YUI DataTable support.
    • Gallery for YUI Gallery support, including support for published Gallery components as well as the Gallery process in general.
    • Tools for support of YUI’s suite of developer tools such as selleck, shifter, grover, yogi, etc.
    • Everything Else for questions that don’t fit one of the categories above, we’ve got you covered here.
  • yui-deprecated - replaces the `YUI 2.x` forum and the forums of other deprecated products (`YUI Doc`, `Builder`, `YUI PHP Loader`, etc.).
  [ 15 posts ] Go to page 1, 2 Next
New Topic | Post Reply | Print view
Previous topic | Next topic

Felipe Gasper

  • Username: fgasper
  • Joined: Mon Aug 02, 2010 1:12 pm
  • Posts: 24
  • GitHub: fgasper
  • Gists: fgasper
  • Offline
  • Profile
Tags:
  • base
  • gist
  • github
  • widget

YUI, hasOwnProperty(), and inheritance

Post Posted: Wed Nov 09, 2011 6:19 am
+0-
YUI cuts off prototype properties of configuration objects, which seems like an unnecessary inconvenience. Here is an example of what I meant.

It’s because of things like this in Base:

Code:
    for (attr in attrs) {
        if (attrs.hasOwnProperty(attr)) {


So, when I’ve done this:

Code:
    var base_config = {
        visible: false
    };

    var instance_a_config = Object.create(base_config);
    instance_a_config.width = "600px";
    var instance = new Y.Widget(instance_a_config);


…then “instance” will not have visible:false, since the hasOwnProperty() check weeds it out.

This doesn’t seem very useful or desirable. As I understand, the intent of the hasOwnProperty() check in YUI is to prevent Object.prototype extensions from bleeding into all object iterations, esp. from Prototype.js. That being the case, ISTM it would be an improvement to check for *exactly* that, rather than killing all inherited properties. Something like:

https://gist.github.com/1351541

Then, we can do this (which seems easier to read anyhow):
Code:
for (var key in obj) {
    if (!Object.gave(key,obj)) { … }


…and we weed out anything added to Object.prototype, without killing off any other inheritance that implementers (ahem!!) may have in mind.

The hasOwnProperty() check seems to prevent implementers from using prototypal inheritance in this way. ISTM a better approach would be to be paradigm-agnostic.

Dav Glass

  • Username: davglass
  • Joined: Thu Aug 28, 2008 9:28 am
  • Posts: 2088
  • Location: Marion, IL, US
  • Twitter: davglass
  • GitHub: davglass
  • Gists: davglass
  • IRC: davglass
  • Offline
  • Profile

Re: YUI, hasOwnProperty(), and inheritance

Post Posted: Wed Nov 09, 2011 6:59 am
+0-
We are looking at adding a Y.Object.flatten (or something similar) to aid in this. You are a very unique case for this and by far not the norm. We would also have to implement Y.Object.gave in order to support more than newer browsers.

Have you filed a ticket? If you've already got a use case & you have a solution a ticket is the place to post this, even better a Pull Request ;)

Satyen Desai

YUI Developer

  • Username: sdesai
  • Joined: Tue Dec 09, 2008 4:17 pm
  • Posts: 302
  • GitHub: sdesai
  • Gists: sdesai
  • YUI Developer
  • Offline
  • Profile
Tags:
  • attribute
  • base
  • dom
  • github
  • utility
  • view
  • yui3

Re: YUI, hasOwnProperty(), and inheritance

Post Posted: Wed Nov 09, 2011 6:19 pm
+0-
I've taken Felipe's view on this in past conversations (https://github.com/rgrove/yui3/commit/6 ... ent-408918).

It's a trade-off.

a) Do we want to remove the fragility [1] from our code, by iterating more than the top-most level in the prototype chain?
b) Do we want to try and protect people from the fragility caused by external code futzing with native prototypes?

Both a) and b) have more than a small chance of causing breakage in the real world.

We're choosing to go with b) and spreading fragility throughout our system, in order to nanny external implementations. I don't think that's the right trade-off option to pick.

There are way more ways in which people can futz with the native JS and DOM environment than just adding onto the Object prototype, and we don't try to nanny all those scenarios. It's a losing battle which we're fighting at the expense of the library's usability.

Flattening objects has the same issues as deciding what the filtering criteria should be if we want to iterate more than the top level properties in the prototype chain. It doesn't really provide a solution in and of itself, but is probably good sugar to have.

Regarding iteration:

For most config iteration [2], whitelists can usually be applied, and I would suggest we change to the non-HOP whitelist mix which I did for parts of Base/Attribute (see github commit discussion link above).

For non-whitelist/open-ended iteration, if we really want to try and play nanny for implementations which mess with Object prototype, we could do something like this which seems like it would probably work for our use cases with minimal overhead, and works across A-Grade:

var OBJECT = {},
p;

for ( p in o ) {
if ( !(p in OBJECT) ) {
// o[p] is good to work with.
}
}

http://yuiblog.com/sandbox/yui/v340/nannying.html

The only issue I see off the top of my head is potentially not iterating native enumerable properties from Object.prototype, which it doesn't seem like we want to do anyway. There may be other issues.

Satyen

[1] Fragility of the type Felipe hit. And by any definition, it is fragility. When you pass an object to a method which asks for an object, you expect the object to be worked on as a whole, not just it's top-most prototype properties - that's just an arbitrary artifact of the nannying trade-off path we chose.

[2] This conversation is not limited to configs of course.

Felipe Gasper

  • Username: fgasper
  • Joined: Mon Aug 02, 2010 1:12 pm
  • Posts: 24
  • GitHub: fgasper
  • Gists: fgasper
  • Offline
  • Profile
Tags:
  • attribute
  • base
  • dom
  • github
  • utility
  • view
  • yui3

Re: YUI, hasOwnProperty(), and inheritance

Post Posted: Mon Nov 14, 2011 9:13 pm
+0-
sdesai wrote:
var OBJECT = {},
p;

for ( p in o ) {
if ( !(p in OBJECT) ) {
// o[p] is good to work with.
}
}


This runs afoul of an edge case where we add a key to Object.prototype that we’ve also added directly to the object, or to an intermediate ancestor … which is why I opted for a prototype chain traversal. With the simple “in” check that you propose here, there would be no way to tell YUI that, yes, even though the prototype has this key, I’ve also added the key to the object itself and *really* do want to include that in the iteration.

I wonder if it would be useful to have:
Y.giver(object, key)
…which would return the “source” of object[key]. Then you could check:
Code:
for (key in obj) if (Y.giver(obj,key) !== Object.prototype) { … }


I don’t know what the potential performance hit is versus the simpler mechanisms in place in YUI currently (HOP) or what Satyen proposes, but ISTM that YUI should accommodate as many use cases as possible, in which case it should specifically weed out properties that come from Object.prototype, and only those.

Satyen Desai

YUI Developer

  • Username: sdesai
  • Joined: Tue Dec 09, 2008 4:17 pm
  • Posts: 302
  • GitHub: sdesai
  • Gists: sdesai
  • YUI Developer
  • Offline
  • Profile

Re: YUI, hasOwnProperty(), and inheritance

Post Posted: Mon Nov 14, 2011 11:41 pm
+0-
As mentioned, the simpler version I provided is designed to weed out properties we may iterate over due to implementations messing with Object.prototype (which is what your edge case describes and is bad practice for the reasons we're discussing), as a replacement for what we were trying to use hasOwnProperty for. That is, if, in your edge case, you don't mess with Object.prototype, then it should work fine.

Performance is a factor. A lot of this iteration happens along critical paths [events, attribute, base etc.] and traversing the prototype chain for each property we iterate is expensive, however A-Grade support is also a factor in using getPrototypeOf (or __proto___).

I agree, ideally if we could identify non-native properties added to Object.prototype across the A-Grade, and just avoid those, that would be perfect.

Short of that, *if* we really want to try and protect people from other implementations which mess with Object.prototype, then the above seems like a reasonable solution given the constraints and pros/cons on the table.

Is the edge case you describe something in your actual implementation?

Felipe Gasper

  • Username: fgasper
  • Joined: Mon Aug 02, 2010 1:12 pm
  • Posts: 24
  • GitHub: fgasper
  • Gists: fgasper
  • Offline
  • Profile

Re: YUI, hasOwnProperty(), and inheritance

Post Posted: Tue Nov 15, 2011 12:09 am
+0-
The edge case isn’t something we’re actually doing, no. (We actually specifically avoid adding to Object.prototype … I still think augmenting that prototype should trigger a warning in ES5.)

For our needs, checking keys of an empty Object instance should work and is definitely better than the HOP check.

Just for my own information, the concern with prototype traversal is purely a performance one, right? Doesn’t every A-grade browser have Object.getPrototypeOf() or .__proto__ ?

Nick Husher

YUI Contributor

  • Offline
  • Profile
Tags:
  • ie7

Re: YUI, hasOwnProperty(), and inheritance

Post Posted: Tue Nov 15, 2011 6:34 am
+0-
I believe IE7 is still considered A-Grade and has no way to determine the prototype of a particular object.

Felipe Gasper

  • Username: fgasper
  • Joined: Mon Aug 02, 2010 1:12 pm
  • Posts: 24
  • GitHub: fgasper
  • Gists: fgasper
  • Offline
  • Profile

Re: YUI, hasOwnProperty(), and inheritance

Post Posted: Tue Nov 15, 2011 7:46 am
+0-
This doesn’t work? (Haven’t tried it…)

Code:
obj.constructor.prototype

Nick Husher

YUI Contributor

  • Offline
  • Profile

Re: YUI, hasOwnProperty(), and inheritance

Post Posted: Tue Nov 15, 2011 7:51 am
+0-
Only if you don't override constructor accidentally or maliciously.

Ryan Grove

YUI Developer

  • Username: rgrove
  • Joined: Tue Dec 09, 2008 9:55 pm
  • Posts: 275
  • Location: Portland, OR
  • Twitter: yaypie
  • GitHub: rgrove
  • Gists: rgrove
  • IRC: rgrove
  • YUI Developer
  • Offline
  • Profile

Re: YUI, hasOwnProperty(), and inheritance

Post Posted: Tue Nov 15, 2011 11:03 am
+0-
It may be helpful to boil this discussion down to some simple truths.

1. There is no reliable way to determine the prototype of an object across all A-grade browsers.

2. Pollution of Object.prototype (or the prototypes of other objects) by misbehaving libraries and uneducated developers is a real-world problem. I've run into it myself even on tightly-controlled codebases where it was the last thing I'd expect, and YUI has had bugs filed by users whenever we've failed to be defensive about this.

3. Some users know that prototype pollution is not an issue in their codebase or in their specific use cases, or are willing to accept the risk of using unfiltered enumeration.

Now, my opinions.

Things that YUI does, especially in the core utilities, should be reasonably safe by default. Given the impossibility of automatically determining whether to include prototype properties in enumeration, the safest course of action is to use hasOwnProperty filtering by default.

This is a tradeoff. We avoid the problem of prototype pollution, which can result in some pretty nefarious and hard-to-debug problems when there are multiple libraries on a page, but we introduce potential confusion for users who expect prototype properties to be enumerated. I think the latter problem is easier to debug than the former problem, especially if YUI is consistent about this behavior and documents it clearly. Even moreso because I think users in the latter camp are likely to have more advanced knowledge of JS, and are more capable of understanding what's happening.

That said, YUI also needs to allow prototype property enumeration when it's explicitly desired. Whitelists are one way to do this, but serve a narrow use case. Flattening is another way, and serves a broader use case. Both require the user to explicitly opt into the functionality, but I think this is a good thing. It indicates clear intent and understanding, on the user's part, of what's about to happen, so it allows YUI to trust that the user knows what they're doing.

I think this is a safe and pragmatic compromise. It may not give everyone exactly what they want, but giving everyone what they want all the time is impossible, and any library that tries to do that quickly devolves into an unmanageable tangle of inconsistencies and edge cases.
  [ 15 posts ] Go to page 1, 2 Next
New Topic | Post Reply | Print view
Previous topic | Next topic
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum