> `Object.assign` has **nothing to do with inheritance**, that's what I am > saying, not just supporting. > What is my personal position here is that `Object.assign` is the wrong > method/tool/function to do anything prototypal or classical inheritance > related.
Are we entirely missing each other? I’ve said a few times now: it’s _none_ of the callee’s business if I use inheritance in my options, config, setup or any other plain object (one without behavior). Object.assign must honor that. I asked in my first email: What is the problem to which ignoring inherited properties is the solution to? If you have an argument that I haven’t refuted yet, please share. Just search GitHub’s code for assign usage and you’ll see it fucking up inheritance all over the place. There’s even a IO.js issue for the same problem that I’m definitely going to help fix: https://github.com/iojs/io.js/issues/62. Andri Möll: > Nah, I’m saying inheritance is an implementation detail of my object. It’s > none of the receiver’s/callee’s business how I implemented that particular > interface (any agreed upon set of properties _is_ an interface). But the > moment someone passes my object to Object.assign, they get the wrong output. > Even if it should’ve been a no-op: `options = Object.assign({}, options)`. > > Ignores getters? You mean merely reads them? That’s not ignoring. Getters are > an implementation detail of an interface. > Prototypes aren't only useful for sharing behavior. They’re just as useful > for data objects and value types. Nothing breaks when you clone or assign > them around. > > > Inheritance? Inheritance is an implementation detail. A function receiving an > object must not care about its inheritance tree as long as it fulfills the > required interface. That’s what the LSP says as well. Even though JavaScript > has no explicit concept of interfaces or types, they’re implicit in any > function call. A. On Feb 27, 2015, at 23:13, Andrea Giammarchi <[email protected]> wrote: > FWIW I do like prototypal inheritance ... but ... > > On Fri, Feb 27, 2015 at 8:45 PM, Andri Möll <[email protected]> wrote: >> That is not what people relying in Object.assign and ES6 will write, because >> you cannot define properties in a generic class, only methods. > > Classes are just syntactic sugar over prototypes after all. > > except finally these behave like natives always have: non enumerable methods > / accessors ... those that even you said don't want on your way > > > I’m definitely going to continue promoting use of plain old prototypical > approaches in addition to that because they're simple and elegant: > > objects will still be used for composing and whenever you > `Object.create(Object.getPrototypeOf(other))` you are still using prototypal > inheritance. > > None of this has ever been solved in `Object.assign` though ... > > > why waste computation power in constructors when you can do so once on the > prototype. > > 'cause 99% of the time you need to initialize your PERSON with a `name` > property, as example ... do that in the object creation through an implicit > initializer as constructor is: done! > > > I find that an advantage of prototypal languages over classical ones. > > I guess you like `init` methods too then > > > > > A bit of a plug in this regard, check out this simple observable > implementation that supports inheritance: https://github.com/moll/js-concert > Boy does this save computation. No need to bind listeners for every object > (e.g. domain model) instance: > Model.prototype.on(“change”, onChange) is all you need. Beautiful, isn’t it? > ;-) > > Check what DOM offered since about ever: EventListener interface: > http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener > > You inherit this: > > ```js > > class EventListener { > handleEvent(e) { > var type = 'on' + e.type; > if (type in this) this[type](e); > } > } > > ``` > > And BOOM, every class inheriting that will be able to create instances usable > as handlers, no need bind listeners to anything anymore! > > ```js > > class DaClicker extends EventListener { > constructor(el) { > el.addEventListener('click', this); > } > onclick(e) { > alert([e.type, this instanceof DaClicker]); > } > } > > var driver = new DaClicker(document); > > ``` > > How cool is that? Now, let's go back to `Object.assign` ... > > > > Well, that didn’t seem to prevent changing class method enumerability just a > little time ago. > > and didn't affect `Object.assign` behavior ... we all agreed here > enumerability had to be changed in order to be consistent with native classes > and be able to extend them without causing unexpected behaviors ... it was > the last window before breaking classes forever, while `Object.assign` is a > method based on old ES3 concepts that has not much to do with ES6 and that > was never meant to be used to extend objects. It's the wrong tool for the > job, accessors are lost in the process, and everything else is ignored, > including inheritance. > > > > Sweet story you made out of the example. :-) Coming back to non-prose for a > sec, unless you get everyone to ignore Object.assign and use your function, > there’s no point in proposing your functions. That’s what I’ve now repeated > plenty of times. It’s going to hurt _us_ prototype-uses because _others_ will > use Object.assign where they need not. > > There's no point in proposing `Object.assign` to deal with inheritance, > prototypal inheritance, and de-facto extend ability. `Object.assing` has one > well defined use case: copy own enumerable properties, that's it ... > **really** ... that's just it. Good for setup or config options, nothing else! > > > > > Umm, that was already explained by Leon Arnott’s email: Object.assign is > cowpath pavement. Everyone seems to like a for-in assignment helper. Two of > most popular assign/extend implementation mentioned (jQuery, Underscore) have > supported inheritance for _at least_ 7 years. Do you not find that as > evidence “from the field"? > > common extend do not loop over inherited properties, if these do is because > these were written in an era where `Object.getPrototypeOf` and > `Object.setPrototypeOf` where missing. > > You talked about computation power and you want to loop over everything per > each `Object.assign` call ... I am sorry I don't follow you anymore here! > > > > Or am I preaching to the choir? Are you personally already in favor of > supporting inheritance in Object.assign? > > `Object.assign` has **nothing to do with inheritance**, that's what I am > saying, not just supporting. > > > > Given what I’ve read from you so far you won’t be affected by it as it seems > to me you prefer to use this prototypal language in a classical way. > > > No, I do like prototypal inheritance and I love the fact it's still the root > of JS inheritance. > > What is my personal position here is that `Object.assign` is the wrong > method/tool/function to do anything prototypal or classical inheritance > related. > > Developers should understand it, and I am realizing they don't ... like not > at all! > > Best Regards > > > > A. > > On Feb 27, 2015, at 19:51, Andrea Giammarchi <[email protected]> > wrote: > >> That is not what people relying in Object.assign and ES6 will write, because >> you cannot define properties in a generic class, only methods. >> >> Moreover, back to your ES5/3compat example, if you have a person object, you >> **never** inherit name, you always have your own name as you explicitly set >> "John". >> >> You eventually inherit the surname, but that's indeed not your own so it >> should not be copied as such, it should stay there inherited unless you >> explicitly go to the inheritance office (the property descriptor officer) >> and ask for an own surname. >> >> Same is for all people from Estonia, they all inherit their native country >> when born, they have to hide it explicitly at the same "descriptor office" >> in order to make them their own country. >> >> But all this goes down to why/how/where you need to retrieve these info. >> That is the place you log through a for/in in order to reach all exposed >> (read enumerables) properties. >> That is where you log passing whatever it is through the function I've >> written. >> >> Before? country isan accessible info, as the surname and other inherited >> properties eventually would be, and only if re-set on top, will become own >> properties. >> >> At the end of the day, `Object.assign` has been already adopted and >> polyfilled and used for some time now, changing it now will probably break >> all code based on it. >> >> Again, I think this is the first time I hear someone wanting a new method >> being exactly like a for/in ... use for/in if that's what you need ( KISS ? ) >> >> Best Regards >> >> >> On Fri, Feb 27, 2015 at 5:27 PM, Andri Möll <[email protected]> wrote: >>> ES3 these are all enumerable, you don't want methods copied all over your >>> objects each time because that's the entire point of having prototypal >>> inheritance, right? If instead of inheriting and composing you copy >>> everything as enumerable, writable, and configurable, that's your choice, >>> not what I believe we all need. >> >> Umm, that’s one tactic for sharing behavior. Yep. But I thought we agreed >> Object.assign is more useful for data/record objects than for objects with >> behavior. Ignoring inheritance because of methods is not an argument then. >> >>> You yourself said one shouldn’t use Object.assign for objects with behavior >>> in the inheritance chain. And I agree. It’s pretty much only useful for >>> data objects (a.k.a plain). Those have no methods in the inheritance chain >>> one needs to ignore. >>> >>> meaning you are good to go with assign or the function I wrote for you. >> >> >> Sadly not. Inheritance should not be conflicted with sharing behavior >> (methods). Entirely orthogonal concepts. It’s very useful to inherit from >> various data/record objects and pass those around. The receiver of such an >> object need never know there’s inheritance involved. >> >>> [ 1 ] What is the problem in accessing inherited values? >>> If you don't want to distinguish them, just don't and use a for/in >>> Why do you want now to change Object assign instead of simply using for/in? >>> This requirement is available since 1999 >> >> They thing to remember here is _other people’s code_. My code perfectly >> honors your inheritance chains when iterating or accessing properties. But >> me doing that doesn’t imply everyone else won’t use Object.assign to set up >> their defaults as is very convenient: `person = Object.assign({name: “”, >> age: 0}, person)`. You think they won’t? They already do so with Object.keys >> when it’s entirely unnecessary for 9/10 use-cases. >> >>> You seem to be afraid of inheritance since you want to ignore it and flat >>> all the properties per each copied/enriched object. >>> I am back with previous [ 1 ] question then. >> >> >> Nah, I’m saying inheritance is an implementation detail of my object. It’s >> none of the receiver’s/callee’s business how I implemented that particular >> interface (any agreed upon set of properties _is_ an interface). But the >> moment someone passes my object to Object.assign, they get the wrong output. >> Even if it should’ve been a no-op: `options = Object.assign({}, options)`. >> >>> You can define you r`toJSON` method that returns the result of the for/in >>> based function I've written for you. Is that retarded? >> >> >> I’ll leave JSON out of this discussion. Yeah, I’d like to set >> Object.prototype.toJSON, but I’m afraid there’s code somewhere that depends >> on it serializing only own properties. Ugh. >> >>> Precisely ! So use inheritance instead of flattening/hiding it everywhere. >>> Use dictionaries and for/in when all this does not matter. >> >>> I really don't see, with all possibilities you have to write the way you >>> want, and a function I wrote for you that does what you need, why bothering >>> `Object.assign` >> >> >> But it’s not me who wants to flatten stuff. It’s the people who will write >> functions or APIs that use Object.assign while setting their defaults. I >> don’t mind them flattening, but only if they don’t lose half of the >> properties to inheritance stripping while doing so. >> >> Am I explaining the problem wrong? I’m still surprised there are people who >> don’t find the following behavior retarded: >> >> ``` >> function logPerson(person) { console.log(“%s is from %s.”, person.name, >> person.country) } >> function logTraveler(person) { logPerson(Object.assign({name: “Traveller”}, >> person)) } >> >> var PERSON = {name: “Unnamed”, country: “Estonia"} >> var john = Object.create(PERSON) >> john.name = “John” >> >> logPerson(john) // => John is from Estonia. >> logTraveler(john) // => John is from undefined. >> ``` >> >> While a little contrived, like I said, Object.assign and its equivalents >> from libraries are already used to set defaults. >> Just in case: please don’t propose replacing every Object.create with >> Object.assign. >> >> A. >> >> On Feb 27, 2015, at 18:35, Andrea Giammarchi <[email protected]> >> wrote: >> >>> answering inline ... >>> >>> On Fri, Feb 27, 2015 at 2:22 PM, Andri Möll <[email protected]> wrote: >>>> noone? JSLint doesn't even let you write a for/in loop if you don't have >>>> `obj.hasOwnProperty(key)` in it, and usually nobody wants inherited >>>> properties (included methods from old classes/ahem prototypes) reassigned >>>> everywhere. >>> >>> Huh? Old prototypes? Those prototypes have their properties set as >>> non-enumerable since how long now? >>> >>> nope, I was rather talking about user-land defined "classes" through >>> prototypes. in ES3 these are all enumerable, you don't want methods copied >>> all over your objects each time because that's the entire point of having >>> prototypal inheritance, right? If instead of inheriting and composing you >>> copy everything as enumerable, writable, and configurable, that's your >>> choice, not what I believe we all need. >>> >>> >>> >>> You yourself said one shouldn’t use Object.assign for objects with behavior >>> in the inheritance chain. And I agree. It’s pretty much only useful for >>> data objects (a.k.a plain). Those have no methods in the inheritance chain >>> one needs to ignore. >>> >>> meaning you are good to go with assign or the function I wrote for you. >>> >>> >>> >>> >>> Again, I ask, what is the problem to which ignoring inherited properties is >>> the solution to? >>> >>> >>> >>> [ 1 ] What is the problem in accessing inherited values? >>> >>> If you don't want to distinguish them, just don't and use a for/in >>> >>> Why do you want now to change Object assign instead of simply using for/in? >>> This requirement is available since 1999 >>> >>> >>> >>> I posit everyone wants inherited properties. Just half of the people have >>> been FUDed into being afraid of inheritance. But arguments based on >>> assumptions on what other people want are irrelevant because naive people >>> are easy to influence. >>> >>> You seem to be afraid of inheritance since you want to ignore it and flat >>> all the properties per each copied/enriched object. >>> I am back with previous [ 1 ] question then. >>> >>> >>> >>> JSLint is how Douglas Crockford writes his code. That’s not an argument for >>> right APIs. JSON.stringify is equally retarded with its inconsistent >>> handling of inheritance, but that’s another matter. >>> >>> You can define you r`toJSON` method that returns the result of the for/in >>> based function I've written for you. Is that retarded? >>> >>> Moreover, you can recreate instances at parse time with a specialized >>> reviver: https://gist.github.com/WebReflection/87e41c09691edf9432da >>> Is that retarded? ( maybe this one is :P ) >>> >>> >>> >>> And as I said below: until everyone also prefixes their obj.name uses with >>> hasOwn: `obj.hasOwnProperty(“name”) && obj.name`, skipping inherited >>> properties is a fool’s errand. It causes inconsistent APIs because you >>> don’t run your options et alii objects through inheritance strippers every >>> time. And you shouldn’t. Or does anyone disagree with that? >>> >>> actually, following your logic you should never access that unless you are >>> sure it's also enumerable so ... >>> >>> `obj.hasOwnProperty("name") && obj.propertyIsEnumerable("name") && >>> obj.name`` >>> >>> >>> >>> This is a bigger problem than my use of Object.assign. Proliferation of >>> Object.assign will prevent everyone else from relying on inheritance. And >>> in a prototypal language I find that bad API design. >>> >>> Precisely ! So use inheritance instead of flattening/hiding it everywhere. >>> Use dictionaries and for/in when all this does not matter. >>> >>> I really don't see, with all possibilities you have to write the way you >>> want, and a function I wrote for you that does what you need, why bothering >>> `Object.assign` >>> >>> Best Regards >>> >>> >>> >>> >>> A. >>> >>> On Feb 27, 2015, at 15:40, Andrea Giammarchi <[email protected]> >>> wrote: >>> >>>> noone? JSLint doesn't even let you write a for/in loop if you don't have >>>> `obj.hasOwnProperty(key)` in it, and usually nobody wants inherited >>>> properties (included methods from old classes/ahem prototypes) reassigned >>>> everywhere. >>>> >>>> If you deal with data objects and dictionaries yuo'll always have a flat >>>> structure, right? If you don't care about properties descriptors (getters >>>> and setters) you can always use a for/in >>>> >>>> ``` >>>> function flatEnumerables(a) { >>>> for (var c, k, i = 1; i < arguments.length; i++) { >>>> for (k in (c = arguments[i])) a[k] = c[k]; >>>> } >>>> return a; >>>> } >>>> ``` >>>> This would do what you are looking for (which is the first time I >>>> personally read/hear about somebody wanting `Object.assign` to behave like >>>> a for/in) >>>> >>>> Would that work? >>>> >>>> Best Regards >>>> >>>> >>>> >>>> On Fri, Feb 27, 2015 at 12:56 PM, Andri Möll <[email protected]> wrote: >>>>> You are talking about "flatting" all properties, which is an undesired >>>>> overhead. >>>> >>>> Umm, Object.assign is as it is because of performance? I don’t think it is >>>> nor is that a good reason. Every property access in JavaScript takes >>>> inheritance into account and there are thousands more than a Object.assign >>>> call here and there. >>>> >>>>> But what's bugging me every time more, is that somebody had a very bad >>>>> idea to spread `Object.assign` as something good for inheritance or >>>>> object cloning. >>>>> >>>>> Where does this come from? `Object.assign` retrieves properties and >>>>> ignore getters and setters, is the last tool you want to use as >>>>> substitution principle because it breaks. >>>> >>>> >>>> Ignores getters? You mean merely reads them? That’s not ignoring. Getters >>>> are an implementation detail of an interface. >>>> Prototypes aren't only useful for sharing behavior. They’re just as useful >>>> for data objects and value types. Nothing breaks when you clone or assign >>>> them around. >>>> >>>> Object.assign just read properties from one object and assign them to >>>> another. Something you used to do by hand. It’s just shorter to type >>>> assign(A, B) than type all properties of B out manually. If it’s _not_ >>>> meant to be the function-equivalent of `for (var key in source) >>>> target[key] = source[key]` then that’s too bad as my money is on it’s >>>> going to be used as such. I definitely want to use it for that. >>>> >>>>> But what's bugging me every time more, is that somebody had a very bad >>>>> idea to spread `Object.assign` as something good for inheritance or >>>>> object cloning. >>>> >>>>> Are you dealing with prototypes and `Object.assign` ? You gonna have way >>>>> more problems than a missed flattered structure. >>>>> Can you explain what is your goal ? Wouldn't this work? >>>> >>>> Inheritance? Inheritance is an implementation detail. A function receiving >>>> an object must not care about its inheritance tree as long as it fulfills >>>> the required interface. That’s what the LSP says as well. Even though >>>> JavaScript has no explicit concept of interfaces or types, they’re >>>> implicit in any function call. >>>> >>>> My goal is to save people from having to think every time they call a >>>> function whether this 3rd party function ignores inherited properties or >>>> not. If the callee uses Object.assign, it strips them out, if not, the >>>> dot-operator takes it into account. Surely no-one’s expecting everyone to >>>> prefix _every_ obj.name use with hasOwn: `obj.hasOwnProperty(“name”) && >>>> obj.name`. Why do it in Object.assigns then is beyond me. Inconsistent and >>>> uncalled for. >>>> >>>> A. >>>> >>>> On Feb 27, 2015, at 14:24, Andrea Giammarchi <[email protected]> >>>> wrote: >>>> >>>>> You are talking about "flatting" all properties, which is an undesired >>>>> overhead. >>>>> >>>>> ```js >>>>> >>>>> var b = Object.create( >>>>> Object.getPrototypeOf(a) >>>>> ); >>>>> >>>>> Object.assign(b, a); >>>>> >>>>> ``` >>>>> >>>>> But what's bugging me every time more, is that somebody had a very bad >>>>> idea to spread `Object.assign` as something good for inheritance or >>>>> object cloning. >>>>> >>>>> Where does this come from? `Object.assign` retrieves properties and >>>>> ignore getters and setters, is the last tool you want to use as >>>>> substitution principle because it breaks. >>>>> >>>>> `Object.assign` is good only to define enumerable, writable, and >>>>> configurable properties, like configuration or setup objects. >>>>> >>>>> Are you dealing with prototypes and `Object.assign` ? You gonna have way >>>>> more problems than a missed flattered structure. >>>>> >>>>> Can you explain what is your goal ? Wouldn't this work? >>>>> >>>>> ```js >>>>> >>>>> var a = {}; // or anything else >>>>> >>>>> var b = Object.create( >>>>> Object.getPrototypeOf(a) >>>>> ); >>>>> >>>>> Object.getOwnPropertyNames(a).forEach(function (k) { >>>>> Object.defineProperty(b, k, Object.getOwnPropertyDescriptor(a, k)); >>>>> }); >>>>> >>>>> ``` >>>>> >>>>> >>>>> Best Regards >>>>> >>>>> >>>>> >>>>> On Fri, Feb 27, 2015 at 11:52 AM, Andri Möll <[email protected]> wrote: >>>>> Hello, >>>>> >>>>> Why does Object.assign ignore inherited enumerable properties? >>>>> What is the problem to which ignoring inherited properties is the >>>>> solution to? >>>>> >>>>> All I can see is that it prevents a useful use of inheritance. The Liskov >>>>> substitution principle was mentioned 27 years ago in ’87. Why is >>>>> Object.assign breaking it? >>>>> >>>>> - Everyone who’s messing with Object.prototype has to do it an >>>>> non-enumerable style anyway. >>>>> - Most uses of Object.assign will likely be for objects with a finite >>>>> number of keys. Those form specific and implicit types from which people >>>>> are likely to read with the dot-operator. That takes inheritance into >>>>> account anyway. >>>>> >>>>> I don’t get the agenda to mess with object inheritance. If one wants >>>>> methods to only be in the parent and data on the child (so Object.assign >>>>> would only copy data), use a classical language. In a >>>>> delegation-prototypal language one should be able to inherit freely >>>>> because of LSP. >>>>> >>>>> Andri >>>>> >>>>> _______________________________________________ >>>>> es-discuss mailing list >>>>> [email protected] >>>>> https://mail.mozilla.org/listinfo/es-discuss >>>>> >>>>> >>>> >>>> >>> >>> >> >> > >
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

