I noticed in https://github.com/joyent/node/pull/3228 TooTallNate used __proto__ but anticipated some resistance to it. Does Node core have a position on __proto__ vs. Object.create? I'm really just curious, and didn't want to clog the pull request with an unrelated question.
The reason __proto__ was used in this case was because SlowBuffer.prototype
already had properties set on it from C++-land, which we don't want to
overwrite.
Indeed, we could read the values from the native SlowBuffer.prototype, call
Object.create() to inherit from Buffer, then copy the native properties
back over to the new prototype. But I figured in this case 1 line of code
wins.
As far as an official stance... I don't want to speak "officially", but
there is already one other place where we set __proto__, and that's on the
"process" object to make it inherit from EventEmitter. Arguably we could do
that same "proper" thing there, and create a true EventEmitter instance in
JS-land and have it be "process", and we copy over the native "process"
properties to that at startup, but we don't. I couldn't tell you why, but I
guess startup speed might be a minute part of it, so I guess the same could
go for Buffer, since that's used at startup as well.
On Mon, May 7, 2012 at 12:30 PM, Domenic Denicola <
dome...@domenicdenicola.com> wrote:
> I noticed in https://github.com/joyent/node/pull/3228 TooTallNate used
> __proto__ but anticipated some resistance to it. Does Node core have a
> position on __proto__ vs. Object.create? I'm really just curious, and
> didn't want to clog the pull request with an unrelated question.
On Monday, May 7, 2012 3:50:17 PM UTC-4, Nathan Rajlich wrote:
> The reason __proto__ was used in this case was because > SlowBuffer.prototype already had properties set on it from C++-land, which > we don't want to overwrite.
Got it. I didn't quite understand what the win was, but after that explanation, it makes sense. I guess this is one of those all-too-frequent cases where __proto__ is more flexible than the standards-committee--approved approach. As ugly as the __'s are, unnecessary property-copying code is probably worse.
The official position is that __proto__ is not allowed.
The official position is also that all official positions are subject
to exception in the rare case that making an exception makes the code
simpler and more performant. TBD whether this case merits such an
exception.
> On Monday, May 7, 2012 3:50:17 PM UTC-4, Nathan Rajlich wrote:
>> The reason __proto__ was used in this case was because
>> SlowBuffer.prototype already had properties set on it from C++-land, which
>> we don't want to overwrite.
> Got it. I didn't quite understand what the win was, but after that
> explanation, it makes sense. I guess this is one of those all-too-frequent
> cases where __proto__ is more flexible than the
> standards-committee--approved approach. As ugly as the __'s are, unnecessary
> property-copying code is probably worse.
On Monday, May 7, 2012 5:56:02 PM UTC-4, Isaac Schlueter wrote:
> The official position is that __proto__ is not allowed.
> The official position is also that all official positions are subject > to exception in the rare case that making an exception makes the code > simpler and more performant. TBD whether this case merits such an > exception.
> Isaac, could you explain the reason __proto__ is not allowed in the core?
> I'm curious, since I see it used often in modules.
> On Monday, May 7, 2012 5:56:02 PM UTC-4, Isaac Schlueter wrote:
>> The official position is that __proto__ is not allowed.
>> The official position is also that all official positions are subject
>> to exception in the rare case that making an exception makes the code
>> simpler and more performant. TBD whether this case merits such an
>> exception.
> __proto__ is marked for depreciation in upcoming ecmascript specs. I think > that is the most common reason you might find.
> Tim.
> On 31 May 2012 08:39, diversario <ilya.shaisulta...@gmail.com> wrote:
>> Isaac, could you explain the reason __proto__ is not allowed in the core? >> I'm curious, since I see it used often in modules.
>> On Monday, May 7, 2012 5:56:02 PM UTC-4, Isaac Schlueter wrote:
>>> The official position is that __proto__ is not allowed.
>>> The official position is also that all official positions are subject >>> to exception in the rare case that making an exception makes the code >>> simpler and more performant. TBD whether this case merits such an >>> exception.
__proto__ is likely going to be in the ES6 spec as at least normative optional. Recent discussions indicated there's some chance it will become full-fledged part of the spec.
I'm only just now reading this thread. But I want to add a couple of comments about __proto__. I've been doing a lot of messing around with inheritance patterns in js. I've come to feel that using __proto__ is useful in only a few rare cases and there are usually more standard ways to accomplish what you want. For instance, in the above pull request would this not work?
This gives SlowBuffer a prototype that inherits from the Buffer.prototype. And additional methods can still be added afterwards. Is this pattern a problem with objects surfaced from addons? If so, can someone give details?
Basically the way to manipulate proto chains is Object.create and the way to retrieve the prototype of an instance is Object.getPrototypeOf. Unwieldy, I know, but standardized. And these shouldn't require any significant perf overhead compared to __proto__. If they do, the v8 team should be incentivized to make them faster. And we've seen that they are willing and able to do that.
Having full fidelity to manipulate __proto__ of an object instance causes all sorts of headaches. It makes it really difficult to reason about the makeup of an objects properties. The example in the pull requests is simple enough obviously, but if the example is simple enough, __proto__ shouldn't even really be necessary. My feeling is that object properties should be Own properties, or they should be part of a sensible proto chain built with standard patterns.
On Sunday, June 10, 2012 2:04:20 PM UTC-7, Brandon Benvie wrote:
> __proto__ is likely going to be in the ES6 spec as at least normative > optional. Recent discussions indicated there's some chance it will become > full-fledged part of the spec.
That option won't work in this case, because we need
SlowBuffer.prototype to be the exact same object returned from C++.
It could be worked around, but would be even worse (in our estimation,
at least) than using __proto__.
Obviously that could change in a future version of V8 if __proto__
usage becomes slow or unsupported.
But in general, I agree with all the very good points you make here,
which is why I commented initially that __proto__ setting is against
the rules, but in this case, the cost of breaking the rule is lower
than the cost of following it.
On Mon, Jun 11, 2012 at 12:06 PM, Marco Rogers <marco.rog...@gmail.com> wrote:
> I'm only just now reading this thread. But I want to add a couple of
> comments about __proto__. I've been doing a lot of messing around with
> inheritance patterns in js. I've come to feel that using __proto__ is useful
> in only a few rare cases and there are usually more standard ways to
> accomplish what you want. For instance, in the above pull request would this
> not work?
> This gives SlowBuffer a prototype that inherits from the Buffer.prototype.
> And additional methods can still be added afterwards. Is this pattern a
> problem with objects surfaced from addons? If so, can someone give details?
> Basically the way to manipulate proto chains is Object.create and the way to
> retrieve the prototype of an instance is Object.getPrototypeOf. Unwieldy, I
> know, but standardized. And these shouldn't require any significant perf
> overhead compared to __proto__. If they do, the v8 team should be
> incentivized to make them faster. And we've seen that they are willing and
> able to do that.
> Having full fidelity to manipulate __proto__ of an object instance causes
> all sorts of headaches. It makes it really difficult to reason about the
> makeup of an objects properties. The example in the pull requests is simple
> enough obviously, but if the example is simple enough, __proto__ shouldn't
> even really be necessary. My feeling is that object properties should be Own
> properties, or they should be part of a sensible proto chain built with
> standard patterns.
> :Marco
> On Sunday, June 10, 2012 2:04:20 PM UTC-7, Brandon Benvie wrote:
>> __proto__ is likely going to be in the ES6 spec as at least normative
>> optional. Recent discussions indicated there's some chance it will become
>> full-fledged part of the spec.
The reason Object.create() wouldn't work in this case is because we don't
want to overwrite the native C++ binding functions from the "native"
SlowBuffer.prototype.
We could have gotten away with Object.create() if we 1) save a reference to
the original SlowBuffer.prototype, then 2) overwritten SlowBuffer.prototype
using Object.create(), and finally 3) loop over the original prototype and
copy over all properties manually.
So for brevity's sake, __proto__ wins here.
On Mon, Jun 11, 2012 at 1:17 PM, Marco Rogers <marco.rog...@gmail.com>wrote:
That makes sense. That got me to thinking if there was a way to have the SlowBuffer properly inherit from Buffer in C++ land. Essentially do the equivalent of Object.create in C++ land *before* you add the native methods to the SlowBuffer.prototype.
Yes that approach is even less simple and transparent. I agree that __proto__ wins in this case. But that might point to deficiencies in the v8 api and it would be interesting to explore how it could be improved.
But then I took a closer look at what was going on with Buffer and SlowBuffer. There's lots of bad juju there :) It looks like that whole situation is kinda screwed and it's best to keep things as simple as possible.
On Monday, June 11, 2012 3:33:38 PM UTC-7, Nathan Rajlich wrote:
> Marco,
> The reason Object.create() wouldn't work in this case is because we don't > want to overwrite the native C++ binding functions from the "native" > SlowBuffer.prototype.
> We could have gotten away with Object.create() if we 1) save a reference > to the original SlowBuffer.prototype, then 2) overwritten > SlowBuffer.prototype using Object.create(), and finally 3) loop over the > original prototype and copy over all properties manually.
> So for brevity's sake, __proto__ wins here.
> On Mon, Jun 11, 2012 at 1:17 PM, Marco Rogers <marco.rog...@gmail.com>wrote:
>>> That option won't work in this case, because we need >>> SlowBuffer.prototype to be the exact same object returned from C++.
>> Interesting. Can you elaborate on this? Is it due to the weirdness with >> retrieving the right "this" object when in C++ land?