Object.define ==> Object.mixin??

# Allen Wirfs-Brock (12 years ago)

I'm the past we discussed issues surrounding the semantic differences between "put" and "define" and we've agreed to include Object.assign in ES6. We have also discussed Object.define but have not yet made a decision to include it.

Nicholas Zaka recently posted a short article that addresses issues relating to the assign/define distinction www.nczonline.net/blog/2012/12/11/are-your-mixins-ecmascript-5-compatible as they already surface in ES5.

For me, this article reenforces that we really need to have something like Object.define in ES6.

It also made me think that perhaps Object.mixin might be a more intuitive name for such a function.

# Brandon Benvie (12 years ago)

Wholeheartedly agree with this. For library authoring it's a necessity, so a define like function is always the first thing in any .js file I make. The need for library authors is obvious but if I recall the conclusion was that those authors would be able to handle it themselves and to push off on codifying it into the language so popular patterns could emerge. I think that article well outlines how this is actually a need and concern in authoring of non-library code. Specifically, accessors are a part of the language (and are going to see more and more use as ES5 becomes the baseline) and in order to correctly handle those for structure-copying you must use descriptor-aware functions.

# Rick Waldron (12 years ago)

On Tue, Dec 11, 2012 at 12:28 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

I'm the past we discussed issues surrounding the semantic differences between "put" and "define" and we've agreed to include Object.assign in ES6. We have also discussed Object.define but have not yet made a decision to include it.

Nicholas Zaka recently posted a short article that addresses issues relating to the assign/define distinction www.nczonline.net/blog/2012/12/11/are-your-mixins-ecmascript-5-compatible as they already surface in ES5.

For me, this article reenforces that we really need to have something like Object.define in ES6.

It also made me think that perhaps Object.mixin might be a more intuitive name for such a function.

This name is certainly more real-word-friendly.

The example code that follows "A pure ECMAScript 5 version of mixin() would be:" is basically what I imagined Object.define would be, but with a slight modification in that Object.assign returns the target object, so should Object.mixin:

Object.mixin = function(receiver, supplier) { return Object.keys(supplier).reduce(function(receiver, property) { return Object.defineProperty( receiver, property, Object.getOwnPropertyDescriptor(supplier, property) ); }, receiver); };

var a = {}, name = "Rick";

var b = Object.mixin(a, { get name() { return name; } });

console.log( a.name ); // "Rick" console.log( b.name ); // "Rick" console.log( a === b ); // true

# Allen Wirfs-Brock (12 years ago)

On Dec 11, 2012, at 10:00 AM, Rick Waldron wrote:

On Tue, Dec 11, 2012 at 12:28 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote: I'm the past we discussed issues surrounding the semantic differences between "put" and "define" and we've agreed to include Object.assign in ES6. We have also discussed Object.define but have not yet made a decision to include it.

Nicholas Zaka recently posted a short article that addresses issues relating to the assign/define distinction www.nczonline.net/blog/2012/12/11/are-your-mixins-ecmascript-5-compatible as they already surface in ES5.

For me, this article reenforces that we really need to have something like Object.define in ES6.

It also made me think that perhaps Object.mixin might be a more intuitive name for such a function.

This name is certainly more real-word-friendly.

The example code that follows "A pure ECMAScript 5 version of mixin() would be:" is basically what I imagined Object.define would be, but with a slight modification in that Object.assign returns the target object, so should Object.mixin:

Except,

  1. It needs to iterate own keys, not just string valued property names so it will pick up properties whose keys are symbols
  2. It needs to rebind super references
  3. I don't see any reason that it should be restricted to enumerable properties. If the intend is to deprecate enumerable along with for-in then we should be adding new functionality that is sensitive to the state of the enumerable attribute.
# Herby Vojčík (12 years ago)

Rick Waldron wrote:

On Tue, Dec 11, 2012 at 12:28 PM, Allen Wirfs-Brock <allen at wirfs-brock.com <mailto:allen at wirfs-brock.com>> wrote:

It also made me think that perhaps Object.mixin might be a more
intuitive name for such a function.

This name is certainly more real-word-friendly.

The example code that follows "A pure ECMAScript 5 version of mixin() would be:" is basically what I imagined Object.define would be, but with a slight modification in that Object.assign returns the target object, so should Object.mixin:

Yes.

Object.mixin = function(receiver, supplier) { return Object.keys(supplier).reduce(function(receiver, property) { return Object.defineProperty( receiver, property, Object.getOwnPropertyDescriptor(supplier, property) ); }, receiver); };

I know this may look like a nitpick, but, why such clever code? I had the problem reading it (I just skipped it); I see no "reducing" process here. Maybe I am just not functional enough. I wouldn't use inject:into: when doing this in smalltalk, but do:.

What's wrong with forEach followed by return receiver?

# Andrea Giammarchi (12 years ago)

Agreed, getOwnPropertyNames is way more appropriate if the topic is: use all ES5 features for mixins too.

Also, the Nicolas example is potentially disaster prone, not in that specific form, but in the way a getter with private scope access could be.

Imagine many objects using that specific object as mixin with that name getter, if there was a setter too the first one that will use it will overwrite the returned value for all other objects.

I think propertie swith getters and setters will cause as many headaches as objects and arrays in function prototypes did before already but hey, if you know what you are doing, I believe there's no other solution for "universally capable mixin method"

br

# Mark S. Miller (12 years ago)

On Tue, Dec 11, 2012 at 10:12 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Dec 11, 2012, at 10:00 AM, Rick Waldron wrote:

On Tue, Dec 11, 2012 at 12:28 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

I'm the past we discussed issues surrounding the semantic differences between "put" and "define" and we've agreed to include Object.assign in ES6. We have also discussed Object.define but have not yet made a decision to include it.

Nicholas Zaka recently posted a short article that addresses issues relating to the assign/define distinction www.nczonline.net/blog/2012/12/11/are-your-mixins-ecmascript-5-compatible as they already surface in ES5.

For me, this article reenforces that we really need to have something like Object.define in ES6.

It also made me think that perhaps Object.mixin might be a more intuitive name for such a function.

This name is certainly more real-word-friendly.

The example code that follows "A pure ECMAScript 5 version of mixin() would be:" is basically what I imagined Object.define would be, but with a slight modification in that Object.assign returns the target object, so should Object.mixin:

Except,

  1. It needs to iterate own keys, not just string valued property names so it will pick up properties whose keys are symbols
  2. It needs to rebind super references
  3. I don't see any reason that it should be restricted to enumerable properties. If the intend is to deprecate enumerable along with for-in then we should be adding new functionality that is sensitive to the state of the enumerable attribute.

"should not"?

# Rick Waldron (12 years ago)

On Tue, Dec 11, 2012 at 1:12 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Dec 11, 2012, at 10:00 AM, Rick Waldron wrote:

On Tue, Dec 11, 2012 at 12:28 PM, Allen Wirfs-Brock <allen at wirfs-brock.com

wrote:

I'm the past we discussed issues surrounding the semantic differences between "put" and "define" and we've agreed to include Object.assign in ES6. We have also discussed Object.define but have not yet made a decision to include it.

Nicholas Zaka recently posted a short article that addresses issues relating to the assign/define distinction www.nczonline.net/blog/2012/12/11/are-your-mixins-ecmascript-5-compatible as they already surface in ES5.

For me, this article reenforces that we really need to have something like Object.define in ES6.

It also made me think that perhaps Object.mixin might be a more intuitive name for such a function.

This name is certainly more real-word-friendly.

The example code that follows "A pure ECMAScript 5 version of mixin() would be:" is basically what I imagined Object.define would be, but with a slight modification in that Object.assign returns the target object, so should Object.mixin:

Except,

  1. It needs to iterate own keys, not just string valued property names so it will pick up properties whose keys are symbols
  2. It needs to rebind super references
  3. I don't see any reason that it should be restricted to enumerable properties. If the intend is to deprecate enumerable along with for-in then we should be adding new functionality that is sensitive to the state of the enumerable attribute.

Agreed with all three points.

# Allen Wirfs-Brock (12 years ago)

On Dec 11, 2012, at 10:19 AM, Mark S. Miller wrote:

On Tue, Dec 11, 2012 at 10:12 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

Except,

  1. It needs to iterate own keys, not just string valued property names so it will pick up properties whose keys are symbols
  2. It needs to rebind super references
  3. I don't see any reason that it should be restricted to enumerable properties. If the intend is to deprecate enumerable along with for-in then we should be adding new functionality that is sensitive to the state of the enumerable attribute.

"should not"?

Right, should not!

# Rick Waldron (12 years ago)

On Tue, Dec 11, 2012 at 1:27 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

  1. It needs to rebind super references
  2. I don't see any reason that it should be restricted to enumerable properties. If the intend is to deprecate enumerable along with for-in then

we should be adding new functionality that is sensitive to the state of the

enumerable attribute.

"should not"?

Right, should not!

To clarify, I assumed you meant "should not", based on the rationale and that is what I was agreeing to.

# Allen Wirfs-Brock (12 years ago)

On Dec 11, 2012, at 10:19 AM, Andrea Giammarchi wrote:

Agreed, getOwnPropertyNames is way more appropriate if the topic is: use all ES5 features for mixins too.

Also, the Nicolas example is potentially disaster prone, not in that specific form, but in the way a getter with private scope access could be.

Imagine many objects using that specific object as mixin with that name getter, if there was a setter too the first one that will use it will overwrite the returned value for all other objects.

I think propertie swith getters and setters will cause as many headaches as objects and arrays in function prototypes did before already but hey, if you know what you are doing, I believe there's no other solution for "universally capable mixin method"

I had a proposal for creating accessors that would only over-ride half of an inherited get/set pair: harmony:object_initialiser_super#super_in_accessor_property_definitions

I let it fade away because, 1) it was kind of ugly, and 2) there were other more important things to put energy into.

# Andrea Giammarchi (12 years ago)

what I think is a very valid use case for mixins based on ES5 features

var MixIt = Object.defineProperties({}, { name: { enumerable: true, get: function () { // notify or do stuff return this._name; }, set: function (_name) { // notify or do stuff this._name = _name; } }, _name: { writable: true } });

while super is unknown concept in ES5 but if de-sugared as Constructor.prototype.method.call(this, argN) in ES6 then is implicitly valid/doesn't need to be modified?

br

# Brandon Benvie (12 years ago)

Works well as an arrow function due to not needing to turn it into a block body, although forEach and a comma would work too.

Object.mixin = (target, source) => Object.keys(source).reduce((target, key) => Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)) ), target);

# Herby Vojčík (12 years ago)

Brandon Benvie wrote:

Works well as an arrow function due to not needing to turn it into a block body, although forEach and a comma would work too.

Object.mixin = (target, source) => Object.keys(source).reduce((target, key) => Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)) ), target);

Ah. Yeah. Guess I am really not very much functional. Probably the unneeded ever-copied same result-to-argument premature optimization was ringing, too.

# Andrea Giammarchi (12 years ago)

agreed, and actually one of the best case I've seen in a while for Array#reduce.

Can I write this as it should be for those who'll read one day later on and making it also static ?

"mixin" in Object || Object.defineProperty(Object, "mixin", { value: function mixin(target, source) { return Object.getOwnPropertyNames(source).reduce(function (target, name) { return Object.defineProperty( target, name, Object.getOwnPropertyDescriptor(source, name) ); }, target); } });

also thinking about try/catch to avoid mixin overwrite ... I believe it's OK if that throws an error but then it should throw regardless if the target object had already that property defined ?

br

# Brandon Benvie (12 years ago)

Ah yes errors. It should probably have similar semantics to how defineProperties works now...attempting each property and holding errors until the end, no? Same for assign.

function mixin(target, source){ if (Type(target) !== 'Object') throw new TypeError ("target must be an object"); if (Type(source) !== 'Object') throw new TypeError("source must be an object");

var error; Object.keys(source).forEach(function(key){ // or getOwnPropertyNames? try { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); } catch (e) { error || (error = e); } });

if (error) throw error; return target; }

# Andrea Giammarchi (12 years ago)

a single property from a mixin that cannot be defined could compromise entirely the behavior so I would actually throw instantly then I believe no try catch is even necessary there, correct?

# John J Barton (12 years ago)

On Wed, Dec 12, 2012 at 9:42 AM, Brandon Benvie <brandon at brandonbenvie.com>wrote:

Ah yes errors. It should probably have similar semantics to how defineProperties works now...attempting each property and holding errors until the end, no? Same for assign.

No, we want early errors and accurate line numbers.

function mixin(target, source){ if (Type(target) !== 'Object') throw new TypeError ("target must be an object");

No, Object.keys() will report TypeError: Object.keys called on non-object

if (Type(source) !== 'Object') throw new TypeError("source must be an object");

var error; Object.keys(source).forEach(function(key){ // or getOwnPropertyNames? try { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); } catch (e) { error || (error = e); } });

if (error) throw error; return target; }

But most of all we want this feature to land and not just spin around here.

jjb

# Allen Wirfs-Brock (12 years ago)

On Dec 12, 2012, at 9:50 AM, John J Barton wrote: ...

But most of all we want this feature to land and not just spin around here.

jjb

As Object.mixin or as Object.define??

# Brandon Benvie (12 years ago)

All the Object functions that operate on multiple properties are currently specified using pendingException which reports the first thrown exception after going through all the properties. defineProperties, freeze, etc.

# John J Barton (12 years ago)

On Wed, Dec 12, 2012 at 10:05 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Dec 12, 2012, at 9:50 AM, John J Barton wrote: ...

But most of all we want this feature to land and not just spin around here.

jjb

As Object.mixin or as Object.define??

Object.mixin

jjb

# Allen Wirfs-Brock (12 years ago)

On Dec 12, 2012, at 10:05 AM, Brandon Benvie wrote:

All the Object functions that operate on multiple properties are currently specified using pendingException which reports the first thrown exception after going through all the properties. defineProperties, freeze, etc.

In, ES6. This is a breaking (hopefully nothing) change from ES5 that was suggested by Mark Miller.

The desire is to decrease the non-determinism that an early throw introduces. In the ES6 approach all property updates that can occur will occur, before the exception is thrown instead of leaving the object in a less well defined partially updated state.

# John J Barton (12 years ago)

On Wed, Dec 12, 2012 at 10:18 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Dec 12, 2012, at 10:05 AM, Brandon Benvie wrote:

All the Object functions that operate on multiple properties are currently specified using pendingException which reports the first thrown exception after going through all the properties. defineProperties, freeze, etc.

In, ES6. This is a breaking (hopefully nothing) change from ES5 that was suggested by Mark Miller.

The desire is to decrease the non-determinism that an early throw introduces.

How can multiple calls to Object.mixin with identical state result in different results?

In the ES6 approach all property updates that can occur will occur, before the exception is thrown instead of leaving the object in a less well defined partially updated state.

If an exception is thrown because of an error in Object.mixin, what state is the object in? Will the spec define that state?

jjb

# Brandon Benvie (12 years ago)

Yeah, it makes sense. If a property throws then you're going to end up with a partially completed action either way (unless the very first one fails in the ES5 rules), so it's better to fail predictably. While the iteration order of the keys is defined, in this case it's usually not useful for ending up in a predictable end state in the face of errors.

# Brandon Benvie (12 years ago)

In order to know what the end state will be for any given property, you currently need to know whether every preceding property throws or not. With the ES6 change, there's no interdependence between properties as to whether they'll end up being visited or not.

# Brandon Benvie (12 years ago)

A contrived example but it demonstrates the problem

Object.mixin({}, Proxy({ a: 5, b: 10, c: 20 }, { getOwnPropertyDescriptor(target, key){ if (key === 'b' && Math.random() * .5) { throw 'halt'; } return Reflect.getOwnPropertyDescriptor(target, key); } }));

In ES5 rules there's no way to know whether 'c' will be in the returned object or not, so that demonstrates actual non-determinism. The more common case is a deterministic result that's unobvious to the developer as to be nearly the same effective result.

# Allen Wirfs-Brock (12 years ago)

On Dec 12, 2012, at 10:23 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:18 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Dec 12, 2012, at 10:05 AM, Brandon Benvie wrote:

All the Object functions that operate on multiple properties are currently specified using pendingException which reports the first thrown exception after going through all the properties. defineProperties, freeze, etc.

In, ES6. This is a breaking (hopefully nothing) change from ES5 that was suggested by Mark Miller.

The desire is to decrease the non-determinism that an early throw introduces.

How can multiple calls to Object.mixin with identical state result in different results?

Because the order that the source properties are visited is unspecified. It can differ among implementations and in theory could even differ within a single implementation.

In the ES6 approach all property updates that can occur will occur, before the exception is thrown instead of leaving the object in a less well defined partially updated state.

If an exception is thrown because of an error in Object.mixin, what state is the object in? Will the spec define that state?

Yes, all property additions (to the target object) that can complete will complete.

# John J Barton (12 years ago)

On Wed, Dec 12, 2012 at 10:44 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Dec 12, 2012, at 10:23 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:18 AM, Allen Wirfs-Brock <allen at wirfs-brock.com

wrote:

On Dec 12, 2012, at 10:05 AM, Brandon Benvie wrote:

All the Object functions that operate on multiple properties are currently specified using pendingException which reports the first thrown exception after going through all the properties. defineProperties, freeze, etc.

In, ES6. This is a breaking (hopefully nothing) change from ES5 that was suggested by Mark Miller.

The desire is to decrease the non-determinism that an early throw introduces.

How can multiple calls to Object.mixin with identical state result in different results?

Because the order that the source properties are visited is unspecified. It can differ among implementations and in theory could even differ within a single implementation.

In the ES6 approach all property updates that can occur will occur, before the exception is thrown instead of leaving the object in a less well defined partially updated state.

If an exception is thrown because of an error in Object.mixin, what state is the object in? Will the spec define that state?

Yes, all property additions (to the target object) that can complete will complete.

And I assume then that the exception thrown will be 1) standardized, 2) specify the properties that are undefined on the target as a result of exceptions, and 3) provide those exceptions. That seems to be what we need to have any chance to use this feature.

jjb

# Allen Wirfs-Brock (12 years ago)

On Dec 12, 2012, at 10:10 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:05 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Dec 12, 2012, at 9:50 AM, John J Barton wrote: ...

But most of all we want this feature to land and not just spin around here.

jjb

As Object.mixin or as Object.define??

Object.mixin

What should be the effect of trying to "mixin" a property that already exists (as an own property) of the target object.

Object.define(target,src) would presumably have redefined such properties using the Object.defineProperty rules. Is that what Object.mixin should do. It could, have different rules.

For example, it could simply replace an existing target property (if the existing property is configurable). Or it could skip existing properties or throw an error if a property exists.

Replace is attractive, but it may or may not be what you want for accessor properties. Consider:

var objTarget = {get foo() {/target/...}}); Object.mixin(objTarget, {set foo(v) {/src/...}});

after the mixin do you want objTarget to look like: {set foo(v) {/src/...}} //replace semantics gives you this or {set foo(v) {/src/...}, get foo() {/target/...} } //Object.defineProperty semantics gives you this

# Nicholas C. Zakas (12 years ago)

I'd vote for replacing duplicate properties by default (as I tend to see this as the common case). That being said, the mixin functions I use tend to have an optional third argument that let's you change that behavior, such as:

// regular Object.mixin(receiver,supplier);

// safe Object.mixin(receiver, supplier, true);

# Allen Wirfs-Brock (12 years ago)

On Dec 12, 2012, at 10:52 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:44 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Dec 12, 2012, at 10:23 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:18 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Dec 12, 2012, at 10:05 AM, Brandon Benvie wrote:

All the Object functions that operate on multiple properties are currently specified using pendingException which reports the first thrown exception after going through all the properties. defineProperties, freeze, etc.

In, ES6. This is a breaking (hopefully nothing) change from ES5 that was suggested by Mark Miller.

The desire is to decrease the non-determinism that an early throw introduces.

How can multiple calls to Object.mixin with identical state result in different results?

Because the order that the source properties are visited is unspecified. It can differ among implementations and in theory could even differ within a single implementation.

In the ES6 approach all property updates that can occur will occur, before the exception is thrown instead of leaving the object in a less well defined partially updated state.

If an exception is thrown because of an error in Object.mixin, what state is the object in? Will the spec define that state?

Yes, all property additions (to the target object) that can complete will complete.

And I assume then that the exception thrown will be 1) standardized, 2) specify the properties that are undefined on the target as a result of exceptions, and 3) provide those exceptions. That seems to be what we need to have any chance to use this feature.

It is currently specified as a whatever exception is first thrown by an operation upon an individual property. Those exceptions are specified at a more primitive level.

In general, the ES spec doesn't specify anything about thrown exception other than which specific exception "class" to throw. It does not specify a message or any other added payload.

I'm not sure that there is an actual utilitarian use cause for this behavior. It is more about minimizing non-determinism that might impact interoperability among implementations.

How would throwing early versus throwing late make any different to you?

# John J Barton (12 years ago)

On Wed, Dec 12, 2012 at 11:20 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Dec 12, 2012, at 10:52 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:44 AM, Allen Wirfs-Brock <allen at wirfs-brock.com

wrote:

On Dec 12, 2012, at 10:23 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:18 AM, Allen Wirfs-Brock < allen at wirfs-brock.com> wrote:

On Dec 12, 2012, at 10:05 AM, Brandon Benvie wrote:

All the Object functions that operate on multiple properties are currently specified using pendingException which reports the first thrown exception after going through all the properties. defineProperties, freeze, etc.

In, ES6. This is a breaking (hopefully nothing) change from ES5 that was suggested by Mark Miller.

The desire is to decrease the non-determinism that an early throw introduces.

How can multiple calls to Object.mixin with identical state result in different results?

Because the order that the source properties are visited is unspecified. It can differ among implementations and in theory could even differ within a single implementation.

In the ES6 approach all property updates that can occur will occur, before the exception is thrown instead of leaving the object in a less well defined partially updated state.

If an exception is thrown because of an error in Object.mixin, what state is the object in? Will the spec define that state?

Yes, all property additions (to the target object) that can complete will complete.

And I assume then that the exception thrown will be 1) standardized, 2) specify the properties that are undefined on the target as a result of exceptions, and 3) provide those exceptions. That seems to be what we need to have any chance to use this feature.

It is currently specified as a whatever exception is first thrown by an operation upon an individual property. Those exceptions are specified at a more primitive level.

So the results are not in fact the same across browsers.

In general, the ES spec doesn't specify anything about thrown exception other than which specific exception "class" to throw. It does not specify a message or any other added payload.

I'm not sure that there is an actual utilitarian use cause for this behavior.

That is my objection to the late-exception definition: unless you know which properties failed and why, the mixin result is in an undefined state. The details of the state are not useful.

It is more about minimizing non-determinism that might impact interoperability among implementations.

IMO your best argument would be: To insure interoperable implementations in the presence of unspecified property order and property errors.

I think that argument is weak because all implementation should have the same outcome in the presence of errors: the result is not useful. Nevertheless, I can imaging a use for the interoperability in cross-browser test suites.

How would throwing early versus throwing late make any different to you?

Because 1) late is a waste, the result is undefined anyway, 2) the exception thrown is a lie, the operation did not die on the property reported but continued and failed to die on an unreported number of subsequent properties/

But if you've already decided this, let's move on: we need Object.mixin more than we need one with any particular exception properties.

jjb

# Allen Wirfs-Brock (12 years ago)

On Dec 12, 2012, at 11:40 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 11:20 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Dec 12, 2012, at 10:52 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:44 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Dec 12, 2012, at 10:23 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:18 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

On Dec 12, 2012, at 10:05 AM, Brandon Benvie wrote:

All the Object functions that operate on multiple properties are currently specified using pendingException which reports the first thrown exception after going through all the properties. defineProperties, freeze, etc.

In, ES6. This is a breaking (hopefully nothing) change from ES5 that was suggested by Mark Miller.

The desire is to decrease the non-determinism that an early throw introduces.

How can multiple calls to Object.mixin with identical state result in different results?

Because the order that the source properties are visited is unspecified. It can differ among implementations and in theory could even differ within a single implementation.

In the ES6 approach all property updates that can occur will occur, before the exception is thrown instead of leaving the object in a less well defined partially updated state.

If an exception is thrown because of an error in Object.mixin, what state is the object in? Will the spec define that state?

Yes, all property additions (to the target object) that can complete will complete.

And I assume then that the exception thrown will be 1) standardized, 2) specify the properties that are undefined on the target as a result of exceptions, and 3) provide those exceptions. That seems to be what we need to have any chance to use this feature.

It is currently specified as a whatever exception is first thrown by an operation upon an individual property. Those exceptions are specified at a more primitive level.

So the results are not in fact the same across browsers.

The effect of upon the target object will be the same. The exception thrown (in the absence of the use of Proxies) will always be a TypeError. The only variations is which property might me named in the implementation dependent text that might be attached to such TypeErrors.

In general, the ES spec doesn't specify anything about thrown exception other than which specific exception "class" to throw. It does not specify a message or any other added payload.

I'm not sure that there is an actual utilitarian use cause for this behavior.

That is my objection to the late-exception definition: unless you know which properties failed and why, the mixin result is in an undefined state. The details of the state are not useful.

It is more about minimizing non-determinism that might impact interoperability among implementations.

IMO your best argument would be: To insure interoperable implementations in the presence of unspecified property order and property errors.

Basically, that is the same argument. Except that the property errors are specified. It is the order that is unspecified.

I think that argument is weak because all implementation should have the same outcome in the presence of errors: the result is not useful. Nevertheless, I can imaging a use for the interoperability in cross-browser test suites.

How would throwing early versus throwing late make any different to you?

Because 1) late is a waste, the result is undefined anyway, 2) the exception thrown is a lie, the operation did not die on the property reported but continued and failed to die on an unreported number of subsequent properties/

Arguably, the operation didn't "die" at all. Instead it made a best effort to do everything that was requested that could possibly be done. I'll leave it to MarkM , if he wants to make more of a case.

# Mark S. Miller (12 years ago)

On Wed, Dec 12, 2012 at 11:57 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

How would throwing early versus throwing late make any different to you?

Because 1) late is a waste, the result is undefined anyway, 2) the exception thrown is a lie, the operation did not die on the property reported but continued and failed to die on an unreported number of subsequent properties/

Arguably, the operation didn't "die" at all. Instead it made a best effort to do everything that was requested that could possibly be done. I'll leave it to MarkM , if he wants to make more of a case.

I don't know that I have anything to add to the arguments already made in this thread -- and I consider those arguments sufficient.

As to the above argument against, I don't understand it. In the absence of proxies and with a non-deterministic update order, any outcome by the new proposed ES6 rule is an allowed outcome by the ES5 rule. In this sense, it is not even a breaking change. The only remaining objection above I see is "is a waste". I don't care about a bit of extra runtime overhead in the thrown-error case.

# Andrea Giammarchi (12 years ago)

I think the latter should replace the previous as overwrite and would not care much about same property name with only a getter VS only a setter. If a developer wants both it can use mixin() to define the descriptor.

Back to Nicolas third parameter, true is not as powerful as a function(target, name, newDescriptor) => objectDescriptor that will

eventually let a developer decide if the newDescriptor should be used or the old one, regardless possible errors caused if target.getOwnPropertyDescriptor(name) cannot be overwritten . In this case the developer might intercept the case and decide if merge descriptors retrieving the currentOne, if any, return the current one, if any, or return the new one regardless.

Thoughts?

# John J Barton (12 years ago)

On Wed, Dec 12, 2012 at 11:13 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Dec 12, 2012, at 10:10 AM, John J Barton wrote:

On Wed, Dec 12, 2012 at 10:05 AM, Allen Wirfs-Brock <allen at wirfs-brock.com

wrote:

On Dec 12, 2012, at 9:50 AM, John J Barton wrote: ...

But most of all we want this feature to land and not just spin around here.

jjb

As Object.mixin or as Object.define??

Object.mixin

What should be the effect of trying to "mixin" a property that already exists (as an own property) of the target object.

Object.define(target,src) would presumably have redefined such properties using the Object.defineProperty rules. Is that what Object.mixin should do. It could, have different rules.

For example, it could simply replace an existing target property (if the existing property is configurable). Or it could skip existing properties or throw an error if a property exists.

Replace is attractive, but it may or may not be what you want for accessor properties. Consider:

var objTarget = {get foo() {/target/...}}); Object.mixin(objTarget, {set foo(v) {/src/...}});

after the mixin do you want objTarget to look like: {set foo(v) {/src/...}} //replace semantics gives you this or {set foo(v) {/src/...}, get foo() {/target/...} } //Object.defineProperty semantics gives you this

The general character of Object.mixin is to produce an object with all of the properties of both arguments. In the case of duplicate properties we want replace LHS with RHS. In my opinion your example is not such a duplicate. Rather we have two functions one on each argument. I would expect the general character to apply: two functions on the result.

Or maybe this should just throw. Either of the above choices will cause surprising errors if the developer expected the other result.

jjb

# Brandon Benvie (12 years ago)

The spec says for the various Object functions that the properties are iterated in "list order". Doesn't this indicate the order is defined?

# Allen Wirfs-Brock (12 years ago)

On Dec 12, 2012, at 2:27 PM, Brandon Benvie wrote:

The spec says for the various Object functions that the properties are iterated in "list order". Doesn't this indicate the order is defined?

Except that the List in question is created "containing the names of each enumerable own property of props" and it doesn't say in what order they are placed when initially populating the list.

# Nathan Wall (12 years ago)

On Dec 11, 2012, at 10:19 AM, Andrea Giammarchi wrote:

Agreed, getOwnPropertyNames is way more appropriate if the topic is: use all ES5 features for mixins too.

I totally agree as well.

Also, the Nicolas example is potentially disaster prone, not in that specific form, but in the way a getter with private scope access could be.

Imagine many objects using that specific object as mixin with that name getter, if there was a setter too the first one that will use it will overwrite the returned value for all other objects.

I think propertie swith getters and setters will cause as many headaches as objects and arrays in function prototypes did before already but hey, if you know what you are doing, I believe there's no other solution for "universally capable mixin method"

Possibly, however, symbols are the solution to the headache right? With the introduction of symbols, we're able to easily tie internal state to objects rather than scope.

var $name = new Symbol();

var Person = {         get name() {             return this[$name];         },         set name(value) {             this[$name] = value;         }     };

var John = Object.mixin({ }, Person);     John.name = 'John';

var Sam = Object.mixin({ }, Person);     Sam.name = 'Sam;

John.name; // => 'John'     Sam.name;  // => 'Sam'

Nathan