Closed
Bug 642500
Opened 14 years ago
Closed 14 years ago
Remove mutable __proto__
Categories
(Core :: JavaScript Engine, defect)
Core
JavaScript Engine
Tracking
()
RESOLVED
WONTFIX
People
(Reporter: bhackett1024, Assigned: evilpie)
References
Details
(Keywords: sec-want)
Allowing scripts to mutate the prototype of pretty much any object makes it harder to reason about the behavior of a script and makes VM, JIT, and analysis implementation more complex and buggier. Type inference has had several bugs due to mutable __proto__ and cannot maintain several desirable invariants because of this feature (i.e. 'type sets contain all the possible type objects which can realized for a var/property' and 'JSFunctions have types which are also functions').
The main use of mutable __proto__ seems to be setting the prototype for newborn objects, e.g. { __proto__: foo, ... }. This functionality can be obtained using ES5 syntax as something like:
Object.create2 = function(a, b) {
var res = Object.create(a);
for (var x in b) { if (b.hasOwnProperty(x)) res[x] = b[x]; }
return res;
}
var o = Object.create2(foo, { f:0, g:1, ... });
Are there other use cases for mutable __proto__ to consider?
Comment 1•14 years ago
|
||
> for (var x in b) { if (b.hasOwnProperty(x)) res[x] = b[x]; }
Or use Object.getOwnPropertyNames
Assignee | ||
Updated•14 years ago
|
Assignee: general → evilpies
Comment 2•14 years ago
|
||
__proto__ is now supported by Chrome, Firefox, Safari, Opera, Adobe Flash, Adobe AIR, Rhino, Ringo, Narwhal, & Node.js. It has existed for ~13yrs. I don't understand the repeated call to kill it. The functionality provided by the OP's `Object.create2` is insufficient compared to __proto__'s current abilities.
I use __proto__ as a fallback for creating what I coined "sandboxed natives":
Array2.prototype = [];
Array2.prototype.size = function() { return this.length };
var arr = ['a', 'b', 'c'];
arr.__proto__ = Array2.prototype;
arr.size(); // 3
typeof Array.prototype.size; // undefined
arr[1]; // 'b'; Good.
arr[4] = 'e';
arr; // ['a', 'b', 'c', , 'e']; Great.
arr.length = 3;
arr; // ['a', 'b', 'c']; Fantastic!
({}).toString.call(arr); // [object Array];
// exceed max length
arr.length = Math.pow(2, 32); // throw RangeError;
More reading:
http://msdn.microsoft.com/en-us/scriptjunkie/gg278167
https://github.com/jdalton/fusebox#readme
Comment 3•14 years ago
|
||
> I don't understand the repeated call to kill it.
It introduces a lot of fragility and makes optimization much much more complicated.
> var arr = ['a', 'b', 'c'];
> arr.__proto__ = Array2.prototype;
_This_ sort of thing is why we want to make it impossible to set __proto__, yes....
Comment 4•14 years ago
|
||
> It introduces a lot of fragility and makes optimization
> much much more complicated.
V8 supports __proto__ and seems to be doing rather with optimizations. http://arewefastyet.com/
> _This_ sort of thing is why we want to make it impossible
> to set __proto__, yes....
Why would you want to remove such useful functionality?
If optimization/access is the concern why not allow devs to control __proto__ by Object.defineProperty(), they could set writable/configurable to false.
I could even see having writable as false by default but keeping configurable true for devs who want to opt-in (maybe at the cost of some perf) to it's continued awesome use.
Comment 5•14 years ago
|
||
> V8 supports __proto__ and seems to be doing rather with optimizations.
Yes, the point is that we can do much better than that.
> Why would you want to remove such useful functionality?
Because it's non-standard, sort of broken by design, and is getting in the way of things we care about?
Comment 6•14 years ago
|
||
> Because it's non-standard,
It's supported by more browsers and environments than ES5, CSS3, or pretty much anything else for that matter ;D
If anything qualifies as a de facto standard, __proto__ is it.
> sort of broken by design, and is getting in the way of things we care about?
This seems like a lame excuse. JS engines have been getting faster with __proto__ since the beginning. It would be a shame to lose such a valuable and powerful language feature.
Comment 7•14 years ago
|
||
> JS engines have been getting faster with __proto__ since the beginning.
Yes, and getting even faster would be possible if prototype chains were guaranteed to be immutable.
Reporter | ||
Comment 8•14 years ago
|
||
(In reply to comment #7)
> > JS engines have been getting faster with __proto__ since the beginning.
>
> Yes, and getting even faster would be possible if prototype chains were
> guaranteed to be immutable.
I'm not sure about this; in JIT code we should be able to guard against mutable prototype chains either dynamically with shapes (changing __proto__ changes the shape) or statically with type information (changing __proto__ will deoptimize pretty much all code which could use the affected object).
I hadn't realized mutable __proto__ was a de facto standard across browsers; the argument for removing it would be, yeah, much stronger were it a Mozilla-only thing.
Comment 9•14 years ago
|
||
As JDD demonstrated in comment #2, Object.create can not fully replace the functionality of __proto__.
> Because it's non-standard, sort of broken by design, and is getting in the way
of things we care about?
The fact that it’s non-standard is really not an argument. If it was, we might as well get rid of String#blink and friends.
If “broken by design” is an issue, let’s drop support for the drag and drop API as well.
The only valid concern here seems to be the “things we care about” part, i.e. performance and simplicity of implementations.
To summarize, here’s the issue as I see it:
Reasons to keep __proto__ mutable:
* Functionality that cannot be replicated using Object.create or anything else
* Interoperability / parity with all other major browsers
Reasons to remove mutable __proto__:
* Reduce complexity of VM, JIT, and analysis implementations, potentially leading to performance gains
I have to agree with Brian’s sentiments in comment #8:
> I hadn't realized mutable __proto__ was a de facto standard across browsers;
> the argument for removing it would be, yeah, much stronger were it a
> Mozilla-only thing.
Assignee | ||
Comment 10•14 years ago
|
||
I think moving [[Prototype]] into the shape would make some speed improvements possible, but of course wouldn't fix the problem for type TI.
>JS engines have been getting faster with __proto__ since the beginning.
I think nobody would be upset to remove it either.
Comment 11•14 years ago
|
||
Removing functionality to make the rest perform. Hmmm, doesn't sound so sane !
As an example of this reasoning I know Chrome had bad experience with limiting the "file:" protocol. They thought nobody was interested to have HTML/CSS/Javascript work from a CD or an SD card.
I am really disappointed seeing how others are completely sure about something (already implemented for years) is not used by simply looking to some web logs.
Comment 12•14 years ago
|
||
(In reply to comment #2)
> __proto__ is now supported by Chrome, Firefox, Safari, Opera, Adobe Flash,
> Adobe AIR, Rhino, Ringo, Narwhal, & Node.js. It has existed for ~13yrs. I don't
> understand the repeated call to kill it. The functionality provided by the OP's
> `Object.create2` is insufficient compared to __proto__'s current abilities.
>
> I use __proto__ as a fallback for creating what I coined "sandboxed natives":
>
> Array2.prototype = [];
> Array2.prototype.size = function() { return this.length };
>
> var arr = ['a', 'b', 'c'];
> arr.__proto__ = Array2.prototype;
> (...)
From what I understand, you're using mutable __proto__ to do Array subclassing.
Subclassing is a very requested use case. I have not come across THE brilliant idea, but I think a thread should be started on the topic at es-discuss. There is already a strawman on it (http://wiki.ecmascript.org/doku.php?id=strawman:array_create). There has been an equivalent discussion on such a method for Function.
I am personnally in favor of removing __proto__ (mutable or not). However, I think that a mechanism to allow standardized subclassing should be added to ECMAScript too.
If such a mechanism is implemented in Firefox BEFORE removing __proto__, then you could use feature detection to do subclassing with one way or another. If at some point, Firefox removes the currently unique subclassing mechanism without providing another alternative, then, it is annoying.
JDD, since you seem to have experience with subclassing, I encourage you to start a thread on the topic on es-discuss. As soon as there is an agreement on the topic, we can fill a bug (B) in order to ask implementation of what has been agreed on. This bug (642500) resolution could then be made dependent on the bug B.
Does that sound like a good idea?
(In reply to comment #9)
> Reasons to keep __proto__ mutable:
>
> * Interoperability / parity with all other major browsers
Does IE have mutable __proto__ now? It doesn't seem to have __proto__ at all, but my IE9 isn't the final version yet.
Comment 14•14 years ago
|
||
David, timeframe? We would like to make a decision on this bug ASAP, because it's blocking various work. We need to either do this, or add a bunch of workarounds for mutable protos.
I don't see your proposal getting us anywhere useful in the next week, say.
Assignee | ||
Comment 15•14 years ago
|
||
They don't have it:
http://kangax.github.com/es5-compat-table/non-standard/
>Does that sound like a good idea?
Everything that makes objects with an changed prototype predictable should be okay.
On think which seems clear to me that the __proto__ syntax is bad not depending on whether we want to allow changing the [[prototype]] or not. We should remove __proto__ asap and make some replacement function and see how much breaks.
Updated•14 years ago
|
OS: Mac OS X → Windows 7
Assignee | ||
Updated•14 years ago
|
Assignee: evilpies → general
Comment 16•14 years ago
|
||
(In reply to comment #14)
> David, timeframe? We would like to make a decision on this bug ASAP, because
> it's blocking various work. We need to either do this, or add a bunch of
> workarounds for mutable protos.
>
> I don't see your proposal getting us anywhere useful in the next week, say.
Indeed, next week is short. However, it's not really about when you make the decision, but more about when you would ship a version without mutable __proto__, which isn't next week.
Regardless, would it possible to consider implementing an Array._create (underscore is important to avoid future collision) method roughly following http://wiki.ecmascript.org/doku.php?id=strawman:array_create
while waiting for an agreement to come out of es-discuss?
Assignee: general → evilpies
OS: Windows 7 → Mac OS X
Comment 17•14 years ago
|
||
(In reply to comment #12)
> snip ...
> Does that sound like a good idea?
David,
an alternative sounds very good during these changes. Removal of any existing
functionality should at least be accompanied by a working alternative.
Pushing things too fast when they have been stable for years should be done
consciously. I don't get all this rush. This does not show much respect for
existing code and their developers who followed published vendor documentation.
Comment 18•14 years ago
|
||
If writable __proto__ was to be replaced with something like `Object.setPrototypeOf`, would that solve implementation complexity issues that comment #1 is talking about?
I understand that this would leave mutable [[Prototype]]'s but at least mutability would be guarded by function call, rather than (harder-to-optimize-i-would-think) `{ __proto__: ... }`.
As JDD points out, ES5 exposes [[Prototype]] via `Object.getPrototypeOf` but only for reading, not writing. Removing __proto__ — which does allow to change [[Prototype]] — would kill that functionality.
__proto__ is certainly used in the wild (from Prototype.js and Fuse.js to Node.js and WebInspector) — http://www.google.com/codesearch?q=__proto__+lang:javascript
Whether it's used for reading or writing is another question. I see that WebCore's inspector relies on writable __proto__; so does Fuse.js. Prototype.js and Node.js, on the other hand, only use it for retrieval (and so can be replaced with `Object.getPrototypeOf`).
Comment 19•14 years ago
|
||
David Bruant,
While Array.create() is better than nothing, __proto__ is useful for more than just arrays. I chose to use arrays as an example because it's popular. As kangax points out writable __proto__ is unique, if __proto__ is removed I would love to see another method added in it's place that allows the same functionality.
Comment 20•14 years ago
|
||
(In reply to comment #13)
>
> Does IE have mutable __proto__ now? It doesn't seem to have __proto__ at all,
> but my IE9 isn't the final version yet.
Mike, I haven't checked IE9 final but when I was there, there was no intent to ever implement __proto__ specifically because we don't want to turn it into a defacto browser standard.
Comment 21•14 years ago
|
||
> If writable __proto__ was to be replaced ... would that solve implementation
> complexity issues
Not particularly. The issue is that the proto chain is mutable at all after the object is first created.
WebCore's inspector is not relevant to us, obviously.
Fuse.js is presumably part of the reason for comment 2.
Comment 22•14 years ago
|
||
I agree that `__proto__` should be removed only if we can provide a viable, alternative mechanism for subclassing native constructors. `Object.create` already implements this for objects; the `Array.create` proposal extends similar functionality to arrays. Using the latter as a precedent, we could hypothetically implement `Function.create`, `RegExp.create`, etc. to allow developers to subclass other native objects. Unfortunately, this is syntactically heavier than simply setting the `__proto__` property, and requires the addition of specialized `create` functions for every native ECMAScript object.
That said, the prevailing sentiment seems to be in favor of keeping `__proto__`, at least until we can agree on a solution to provide equivalent functionality. Also, as both JDD and Diego have noted, `__proto__` is a de facto standard, and implemented by every major browser except Internet Explorer. This might be another point to consider before deprecating or removing it.
Comment 23•14 years ago
|
||
(In reply to comment #18)
> I understand that this would leave mutable [[Prototype]]'s but at least
> mutability would be guarded by function call, rather than
> (harder-to-optimize-i-would-think) `{ __proto__: ... }`.
>
> As JDD points out, ES5 exposes [[Prototype]] via `Object.getPrototypeOf` but
> only for reading, not writing. Removing __proto__ — which does allow to change
> [[Prototype]] — would kill that functionality.
I think that the optimizations would be based on immutable prototype. Imagine how different it is to implement the [[Get]] internal method if the prototype chain can change or not.
A discussion has started on es-discuss on the topic: https://mail.mozilla.org/pipermail/es-discuss/2011-March/013131.html
It seems to be that Fuse's uses can all be met with proxies, by wrapping and forwarding as desired, no? Is that not the case?
(__proto__ at initialization time is indeed not the problem, it's mutation after initialization that adds complexity and runtime cost to engines.)
Comment 25•14 years ago
|
||
(In reply to comment #23)
> (In reply to comment #18)
[...]
> > As JDD points out, ES5 exposes [[Prototype]] via `Object.getPrototypeOf` but
> > only for reading, not writing. Removing __proto__ — which does allow to change
> > [[Prototype]] — would kill that functionality.
> I think that the optimizations would be based on immutable prototype. Imagine
> how different it is to implement the [[Get]] internal method if the prototype
> chain can change or not.
Yeah. I can imagine.
OS: Mac OS X → Windows 7
Comment 26•14 years ago
|
||
(In reply to comment #18)
> If writable __proto__ was to be replaced with something like
> `Object.setPrototypeOf`, would that solve implementation complexity issues that
> comment #1 is talking about?
No, the low level issue benefits come from making the [[Prototype]] immutable at the time of object creation.
There are other proposals being considered for setting [[Prototype]] in an object literal http://wiki.ecmascript.org/doku.php?id=strawman:obj_initialiser_meta
However, for legacy copatability, continuing to {__proto__: Foo.prototype} would be pretty harmless. It is the unconstrained use of LHS __proto__ that is problematic.
>
> As JDD points out, ES5 exposes [[Prototype]] via `Object.getPrototypeOf` but
> only for reading, not writing. Removing __proto__ — which does allow to change
> [[Prototype]] — would kill that functionality.
That was why ES5 defined getPrototypeOf but not setPrototypeOf
I strongly suspect that continuing support of {__proto__ : Foo.prototype} and expeditious addition of Array.create would provide the functionality actually used by the vast majority of assignments to __proto__.
OS: Windows 7 → Mac OS X
Comment 27•14 years ago
|
||
(In reply to comment #23)
> (In reply to comment #18)
> > I understand that this would leave mutable [[Prototype]]'s but at least
> > mutability would be guarded by function call, rather than
> > (harder-to-optimize-i-would-think) `{ __proto__: ... }`.
> >
> > As JDD points out, ES5 exposes [[Prototype]] via `Object.getPrototypeOf` but
> > only for reading, not writing. Removing __proto__ — which does allow to change
> > [[Prototype]] — would kill that functionality.
> I think that the optimizations would be based on immutable prototype. Imagine
> how different it is to implement the [[Get]] internal method if the prototype
> chain can change or not.
>
> A discussion has started on es-discuss on the topic:
> https://mail.mozilla.org/pipermail/es-discuss/2011-March/013131.html
What about only allowing [[Prototype]] assignment at object's creation time ?
Too simple, I know !
Comment 28•14 years ago
|
||
(In reply to comment #27)
>
> What about only allowing [[Prototype]] assignment at object's creation time ?
>
> Too simple, I know !
That is exactly what Object.create, Array.create, and the object/array literal proposals I linked to do.
Comment 29•14 years ago
|
||
> That is exactly what Object.create, Array.create, and the object/array
> literal proposals I linked to do.
I could get behind a generic solution for that. Maybe even an extension of Object.create(). Something like an additional argument or addition to the "Properties" argument. http://es5.github.com/#x15.2.3.5
Comment 30•14 years ago
|
||
(In reply to comment #14)
> David, timeframe? We would like to make a decision on this bug ASAP, because
> it's blocking various work. We need to either do this, or add a bunch of
> workarounds for mutable protos.
>
> I don't see your proposal getting us anywhere useful in the next week, say.
Allen said that there are going to discuss the topic at the next TC-39 meeting: https://mail.mozilla.org/pipermail/es-discuss/2011-March/013143.html
I think the next meeting is in one week or so. Would it be possible to wait until then?
Reporter | ||
Comment 31•14 years ago
|
||
(In reply to comment #30)
> Allen said that there are going to discuss the topic at the next TC-39 meeting:
> https://mail.mozilla.org/pipermail/es-discuss/2011-March/013143.html
> I think the next meeting is in one week or so. Would it be possible to wait
> until then?
I don't think this is super-urgent. The browser works with mutable __proto__ and upcoming features (type inference) support it (though we're still ironing out bugs due to __proto__).
Comment 32•14 years ago
|
||
On es-discuss Oliver Hunt proposed Object.subclass()
https://mail.mozilla.org/pipermail/es-discuss/2011-March/013141.html
While his quick mockup could be tweaked I dig the idea.
Comment 33•14 years ago
|
||
(In reply to comment #0)
> Are there other use cases for mutable __proto__ to consider?
I've been working on a live environment for JavaScript, similar to Self. (I mean "live" in the Smalltalk sense - you write a program by modifying it while it's running.) Modifying an object's __proto__ is an everyday operation when programming in this environment. (For example, I make a Dog object that inherits from the Animal object, and later decide that I want to insert a Mammal object in between. So I create Mammal, and change Dog's __proto__ to point to it.)
I don't necessarily care about whether it can be done *efficiently* - I'll be perfectly happy if the VM assumes that modifying __proto__ is a rare operation. (It's the kind of thing that I do several times a day, not several times a second.) But it would significantly cripple this kind of live environment if it became completely impossible.
(If my explanation isn't clear, I've got an old demo video up at http://vimeo.com/14528098 - I think near the end of the video there's actually a demonstration of modifying an object's __proto__.)
Plus, yeah, all the other browsers can do it. ;)
Comment 34•14 years ago
|
||
(In reply to comment #33)
> (In reply to comment #0)
> > Are there other use cases for mutable __proto__ to consider?
>
> I've been working on a live environment for JavaScript, similar to Self. (I
> mean "live" in the Smalltalk sense - you write a program by modifying it while
> it's running.) Modifying an object's __proto__ is an everyday operation when
> programming in this environment. (For example, I make a Dog object that
> inherits from the Animal object, and later decide that I want to insert a
> Mammal object in between. So I create Mammal, and change Dog's __proto__ to
> point to it.)
Interestingly, no Smalltalk implementation that I am aware of ever had the ability to directly modify the class an existing instances (self may be another matter). Any modification of the class structure would cause recompilation of all subclasses. The system would then either immediately or lazily replace (using the become: primitive) all existing instances from the modified hierarchy with new instances.
Use of the Smalltalk become: primitive in application code (in contrast to the tools or implementation layer) was almost always a red flag indicating that somebody was trying to be too clever. I'm all for a live Smalltalk-style development environment for JavaScript but making [[Prototype]] dynamically mutable (and hence usable in application code) is probably not the best way to get there.
Other than that, I'd love to hear more about your environment.
Comment 35•14 years ago
|
||
(In reply to comment #34)
> Interestingly, no Smalltalk implementation that I am aware of ever had the
> ability to directly modify the class an existing instances (self may be another
> matter). Any modification of the class structure would cause recompilation of
> all subclasses. The system would then either immediately or lazily replace
> (using the become: primitive) all existing instances from the modified
> hierarchy with new instances.
>
> Use of the Smalltalk become: primitive in application code (in contrast to the
> tools or implementation layer) was almost always a red flag indicating that
> somebody was trying to be too clever. I'm all for a live Smalltalk-style
> development environment for JavaScript but making [[Prototype]] dynamically
> mutable (and hence usable in application code) is probably not the best way to
> get there.
>
> Other than that, I'd love to hear more about your environment.
Yup, that's similar to how we usually do it in Self-land. Self does give us the option of making a parent slot dynamically mutable, but usually we don't do that (because it interferes with the VM's optimization tricks and it's usually more confusing than it's worth). Most of the time we make parent slots be constant slots, so that the only way to "change" its contents (which normal applications don't do, but which the Self tools need to be able to do) is by using become:, which requires hopping the reflection fence, so at least it's pretty clear that you're doing some deep magic. (All reflective operations in Self are done through special "mirror" objects. And if you wanted to make sure that regular application code didn't do any reflective stuff, you could simply not include mirrors in the deployed application.) And that'll cause recompilation of any compiled code that assumed that the inheritance structure would stay constant.
Avocado (the live JS environment I'm working on) is a weird case - I consider it a "tool", and it's perfectly reasonable (and necessary) for it to be doing this kind of reflective magic. But I like the fact that it's 100% made of completely ordinary JavaScript code with no special privileges or anything - you just point your web browser to the Avocado website, and presto there's the development environment right there in your browser. I'd be sad if that stopped working in some browsers (or if live environments could only operate in a crippled way in some browsers).
So, personally, I'm OK with the way things are now, but I'd be even happier with a solution that puts the ability (changing an object's parent or calling become: or whatever) behind a clear fence, so that it's still possible for non-privileged JS code to do it, but it's obvious that this is deep magic, and implementations can assume that it's rare and optimize the common case.
(In reply to comment #35)
> I'd be sad if that stopped
> working in some browsers (or if live environments could only operate in a
> crippled way in some browsers).
How does Avocado work around the lack of __proto__ (read or write) in IE9?
Comment 37•14 years ago
|
||
I respectfully suggest this is an absolutely awful idea - especially without a viable replacement.
> Because it's non-standard, sort of broken by design, and is getting in the way
> of things we care about?
Then let's fix it and standardise it, call it "base" or "inherits" or "super" or "whatever" - but don't just remove an incredibly powerful feature like this.
> Yes, and getting even faster would be possible if prototype chains were
> guaranteed to be immutable.
I don't see why a JS prototype chain should be immutable, a JS object was always supposed to be about flexibility and dynamism - this feature offers JS true runtime polymorphism.
Aside as has been mentioned V8 seems to handle this fine from a performance point of view, and my own 30k line library uses it throughout, and I'm constantly amazed how fast SpiderMonkey is, so I just don't buy the "significant" performance argument I'm afraid.
Aside from my love of the dynamism, declaring inline JS inheritance is painful and ugly without:
function sub() {
}
sub.prototype = {
__proto__ : super.prototype
[...]
}
I now will have to use all these (IMO) silly and inelegant "extend()" methods that go round arbitrarily decorating prototype chains, which now have to be called and executed upfront when parsing the JS, rather than when the object is initialised.
It isn't __proto__ that's bust, it's an elegant *inline* declarative inheritance pattern in JavaScript that's broken, and IMO extend() et al isn't it.
Comment 38•14 years ago
|
||
(In reply to comment #36)
> How does Avocado work around the lack of __proto__ (read or write) in IE9?
Well, the real answer is that so far I've just been ignoring IE. :) But once I do get around to supporting it, the plan basically involves either an ugly workaround or an error message. Could hack together a slow, crippled version of "become:" (traverse the entire object graph looking for references to the object, replace with reference to the new object - that won't let me replace references in the local variables of a closure, but it might be good enough most of the time). Or I could show an error message saying, "Sorry, your browser doesn't support this operation; this would work if you were using Safari or Chrome or Firefox."
As for handling the lack of a readable __proto__, I thought there was at least *some* way to get an object's parent. http://msdn.microsoft.com/en-us/library/ff877835(v=vs.94).aspx seems to be what I need. I don't really care whether it's called __proto__ or not.
Comment 39•14 years ago
|
||
(In reply to comment #37)
> Aside as has been mentioned V8 seems to handle this fine from a performance
> point of view, and my own 30k line library uses it throughout, and I'm
> constantly amazed how fast SpiderMonkey is, so I just don't buy the
> "significant" performance argument I'm afraid.
I submit that if you don't have a good deal of knowledge of how polymorphic inline caching works in dynamic languages, saying something performs perfectly well is speaking from a position of incomplete knowledge.
> Aside from my love of the dynamism, declaring inline JS inheritance is painful
> and ugly without:
>
> function sub() {
>
> }
> sub.prototype = {
> __proto__ : super.prototype
> [...]
> }
>
> I now will have to use all these (IMO) silly and inelegant "extend()" methods
> that go round arbitrarily decorating prototype chains, which now have to be
> called and executed upfront when parsing the JS, rather than when the object
> is initialised.
>
> It isn't __proto__ that's bust, it's an elegant *inline* declarative
> inheritance pattern in JavaScript that's broken, and IMO extend() et al isn't
> it.
There's been some discussion of standardizing extended object literal syntax which would allow determining the created object's [[Prototype]], as well as define properties with atypical attributes (e.g. not enumerable, not writable, and/or not configurable):
http://wiki.ecmascript.org/doku.php?id=strawman:object_initialiser_extensions
That would give you an "elegant inline declarative inheritance pattern" without needing to have a special and special-broken __proto__ fake-property to do it.
Comment 40•14 years ago
|
||
(In reply to comment #38)
> As for handling the lack of a readable __proto__, I thought there was at least
> *some* way to get an object's parent.
> http://msdn.microsoft.com/en-us/library/ff877835(v=vs.94).aspx seems to be what
> I need. I don't really care whether it's called __proto__ or not.
Object.getPrototypeOf is standardized. If you want to read the [[Prototype]] of an object, you absolutely should use Object.getPrototypeOf rather than __proto__ (or monkey-patch your own Object.getPrototypeOf based on __proto__, in old browsers that don't support it).
Comment 41•14 years ago
|
||
(In reply to comment #39)
> (In reply to comment #37)
> > Aside as has been mentioned V8 seems to handle this fine from a performance
> > point of view, and my own 30k line library uses it throughout, and I'm
> > constantly amazed how fast SpiderMonkey is, so I just don't buy the
> > "significant" performance argument I'm afraid.
>
> I submit that if you don't have a good deal of knowledge of how polymorphic
> inline caching works in dynamic languages, saying something performs perfectly
> well is speaking from a position of incomplete knowledge.
Absolutely, my entire comment is based on a lack of knowledge of how polymorphic inline caching works in dynamic languages, and neither have I ever committed a line of code to SpiderMonkey (not that I'm proud of that).... but, I stand by my statement, as of 23rd march 2011 V8 is still quicker than SpiderMonkey on Kraken - a mutable __proto__ doesn't appear to be holding it back....
> > It isn't __proto__ that's bust, it's an elegant *inline* declarative
> > inheritance pattern in JavaScript that's broken, and IMO extend() et al isn't
> > it.
> There's been some discussion of standardizing extended object literal syntax
> which would allow determining the created object's [[Prototype]], as well as
> define properties with atypical attributes (e.g. not enumerable, not writable,
> and/or not configurable):
>
> http://wiki.ecmascript.org/doku.php?id=strawman:object_initialiser_extensions
>
> That would give you an "elegant inline declarative inheritance pattern" without
> needing to have a special and special-broken __proto__ fake-property to do it.
I have seen it, personally I'm not a fan of this all encompassing "class/sealed/frozen" approach - now my lovely JavaScript is taking on a distinctly Java/C++ flavour - so I'd dispute the "elegance" ;-) IMO there are probably better ways of implementing much of this functionality without loosing the dynamism of JS and continually bloating the language.
But aside from that, I don't see a reason that such a powerful & useful - "special-broken"/"fake-property" feature or otherwise should be removed when V8 doesn't (appear) to suffer, and there is no viable replacement from ECMA on the horizon.
Reporter | ||
Comment 42•14 years ago
|
||
(In reply to comment #41)
> > I submit that if you don't have a good deal of knowledge of how polymorphic
> > inline caching works in dynamic languages, saying something performs perfectly
> > well is speaking from a position of incomplete knowledge.
>
> Absolutely, my entire comment is based on a lack of knowledge of how
> polymorphic inline caching works in dynamic languages, and neither have I ever
> committed a line of code to SpiderMonkey (not that I'm proud of that).... but,
> I stand by my statement, as of 23rd march 2011 V8 is still quicker than
> SpiderMonkey on Kraken - a mutable __proto__ doesn't appear to be holding it
> back....
You're right, there's no performance argument for removing __proto__, a JS engine can be just as fast with as without it (see comment 8). (though if you actually *do* mutate prototypes, don't expect much performance)
Going to WONTFIX this. I keep coming back to comment 8 (my misunderstanding about how widely used __proto__ is). This would have been nice to remove 10 years ago, but at this point I think it's a non-starter to make things easier for JS engine developers by making things harder and breaking compat for web developers.
Status: NEW → RESOLVED
Closed: 14 years ago
Resolution: --- → WONTFIX
Comment 43•14 years ago
|
||
(In reply to comment #41)
> Absolutely, my entire comment is based on a lack of knowledge of how
> polymorphic inline caching works in dynamic languages, and neither have I ever
> committed a line of code to SpiderMonkey (not that I'm proud of that).... but,
> I stand by my statement, as of 23rd march 2011 V8 is still quicker than
> SpiderMonkey on Kraken - a mutable __proto__ doesn't appear to be holding it
> back....
Correlation is not causation. __proto__ is not the reason V8 is quicker at Kraken. But SpiderMonkey with __proto__ is less efficient in some cases than a SpiderMonkey without mutable __proto__ would be.
> I have seen it, personally I'm not a fan of this all encompassing
> "class/sealed/frozen" approach - now my lovely JavaScript is taking on a
> distinctly Java/C++ flavour - so I'd dispute the "elegance" ;-) IMO there
> are probably better ways of implementing much of this functionality without
> loosing the dynamism of JS and continually bloating the language.
These attributes were always in JS properties (in ES3 as DontEnum, DontDelete, and ReadOnly, each present on some standardized properties even if not available to be used with user-defined properties). If you're frustrated that they're now available to user-defined properties, I suggest the time to be frustrated was two years ago when ES5 was being standardized. This ship has sailed.
> But aside from that, I don't see a reason that such a powerful & useful -
> "special-broken"/"fake-property" feature or otherwise should be removed
> when V8 doesn't (appear) to suffer, and there is no viable replacement from
> ECMA on the horizon.
V8's performance on Kraken has nothing to do with support for __proto__. The only apples-to-apples comparison you can do is between one engine with support for mutable __proto__, and the same engine without support for mutable __proto__, on a variety of tests which highlight __proto__'s trickinesses.
Status: RESOLVED → REOPENED
OS: Mac OS X → Windows 7
Resolution: WONTFIX → ---
Comment 44•14 years ago
|
||
Oops, cleared the WONTFIX, although I disagree with it. Maybe at a later time we can circle back to this after some evangelism work.
Status: REOPENED → RESOLVED
Closed: 14 years ago → 14 years ago
OS: Windows 7 → All
Hardware: x86 → All
Resolution: --- → WONTFIX
Comment 45•14 years ago
|
||
(In reply to comment #42)
> You're right, there's no performance argument for removing __proto__, a JS
> engine can be just as fast with as without it (see comment 8). (though if you
> actually *do* mutate prototypes, don't expect much performance)
Brian is there a middle ground here?
One that implements the "proto" meta property that Jeff pointed to, so that it is immutable after declaration providing declarative inheritance, but __proto__ remains mutable and on you head be it from a perfomance view?
Comment 46•14 years ago
|
||
Not really. __proto__ isn't statically-observable syntax that could be de-optimized or whatever if seen. If __proto__ is available and changeable, everything has to pay the price of object prototype chains potentially changing.
Comment 47•14 years ago
|
||
We could keep this bug around, but it would depend on bug(s) implementing the proposed (or not yet proposed) ES-Harmony replacements for the valid use cases. Easy enough to recreate this bug when we get those bugs actually filed and even patched.
/be
Comment 48•14 years ago
|
||
Perhaps __proto__ could be removed in strict mode, and performance enhancements done there. Though I'm not sure if there are any JIT-time differences that stem from strict mode...
Comment 49•14 years ago
|
||
As much as I understand the argument for removing `__proto__` in strict mode, I'm afraid I have to disagree. The specification makes no stipulations for exposed internal properties, so this may confuse developers; furthermore, I'm wary of removing `__proto__` until we can implement a capable replacement.
You need to log in
before you can comment on or make changes to this bug.
Description
•