Function traits and mixins are the bread and butter of JS. Being able to share functionality is the pumping heart of prototypical inheritance, especially in a behaviorally typed environment.
Much like a possible issue I have with what Rick suggested (although mixins and decoration are not the same) - let's say you have ` Enumerable_first_last.call(arr)` , and then I `.map` or `.filter` that mixed in array - the resulting array no longer has the trait. I can of course call Object.mixin on the result of `.map` and override `.map` on a Enumerable_first_last but that's a tedious process I don't want to have to do for every trait (what if I add several? Do I now have to keep track and compose?) It's an interesting suggestion and a common pattern, but I really hope we can do better. On Mon, Oct 14, 2013 at 12:01 AM, Peter Seliger < peter.seli...@googlemail.com> wrote: > If you really have to live with those restriction you do describe, > there still is a low level solution working since ES 3 that keeps > the implemented codebase of certain behaviors at one place > without effecting any other code - function based traits and mixins. > > One could e.g. write ones own implementations of an > Enumerable's [first], [last] accessors. > > > var Enumerable_first_last = (function () { > > var > Trait, > > first = function () { > return this[0]; > }, > last = function () { > return this[this.length - 1]; > } > ; > > Trait = function () { > > this.first = first; > this.last = last; > }; > > return Trait; > > }()); > > From that point one is free to decide of where to apply that trait. > > var > str = "JavaScript natively supports Traits", > arr = str.split(" "), > coll = { > "0": "foo", > "1": "bar", > "2": "baz", > "length": 2 > } > ; > > It is totally fine to apply additional behavior separately to objects > that are in need of it. > > Enumerable_first_last.call(arr); > > arr.first(); // "JavaScript" > arr.last(); // "Traits" > > Enumerable_first_last.call(coll); > > coll.first(); // "foo" > coll.last(); // "bar" > > One also could delegate this behavior to an objects prototype. > > Enumerable_first_last.call(String.prototype); > // works for all [[String]] implementations that do allow access via [idx] > > str.first(); // "J" > str.last(); // "s" > > This approach in its first step decouples implementation from > having it directly effecting a system. The second step is about > responsibility and making decisions. > > Peter > > > > On Sun, Oct 13, 2013 at 8:47 PM, Benjamin (Inglor) Gruenbaum < > ing...@gmail.com> wrote: > >> > Prollyfilling is great too (perhaps you disagree?), and as its name >> suggests it happens *before* the method is added to the spec. >> >> So in your opinion adding a `.shuffle` method to an Array in a library I >> ship to users is a good idea if it makes my code clearer and nicer? >> >> I'm not saying I disagree, I'm not one of those people who passes an >> extra parameter for `undefined` in a function. I just think it can be very >> risky. >> >> When I have to work on big code bases that run JavaScript end to end >> using multiple frameworks and libraries on both sides, I find that >> extending object prototypes can be _very_ risky - and "Prollyfilling" (nice >> term by the way) has bitten me before. Sure, in _my_ code it can be very >> nice, but I expect libraries to have little to no side effects on my code >> and that's exactly the cases it can bite me. >> >> > How exactly did that example "fail"? The differences in detail hardly >> matter; PrototypeJS trod a cow-path that ES5 paved. Most users don't worry >> about the edge case differences. >> >> I don't think anyone today is doubting the enormous contribution >> PrototypeJS had and `.bind` was very useful in it and is very useful in >> ES5. However, running into edge cases and getting unexpected results is >> something I don't think people appreciate. The SweetJS case is just as >> interesting. >> >> There is no doubt some of the most interesting API additions have come >> from people extending natives and that says something. However, today when >> rather than writing 1000 line pages I see more and more 100 thousand lines >> code bases using multiple libraries - side effects that extending natives >> sound _very_ scary, and being able to extend the natives in a way that does >> not bite me is something I'd _really_ love to play with. >> >> > Don't worry about syntax yet. >> >> Of course, I was just toying around. Like I've said before, pretty much >> anyone else in this discussion is more qualified to come with an actual >> solution than me. >> >> > This must cost, and it does cost. >> >> Would you mind elaborating on that or linking to relevant discussion >> about the last proposal? I'd love to understand the issues involved and get >> a better understanding of the challenges something like this would bring. >> >> >> >> >> On Sun, Oct 13, 2013 at 9:37 PM, Brendan Eich <bren...@mozilla.com>wrote: >> >>> Benjamin (Inglor) Gruenbaum <mailto:ing...@gmail.com> >>>> October 13, 2013 11:00 AM >>>> >>>> Brendan Eich<bren...@mozilla.com <mailto:bren...@mozilla.com>> wrote: >>>> > No, object detection, polyfilling, and even "prollyfilling" are >>>> common and successful adaptationsp on the Web. >>>> >>>> Polyfilling is great _after_ the method has already been added to the >>>> spec. >>>> >>> >>> Prollyfilling is great too (perhaps you disagree?), and as its name >>> suggests it happens *before* the method is added to the spec. >>> >>> >>> I'm completely fine with adding an Array.prototype.map shim to IE8, the >>>> problem with adding a method that's not on the prototype yet is that it'll >>>> fail in case the spec is different from the implementation I chose. If you >>>> mentioned PrototypeJS, its `.bind` method is one such example. >>>> >>> >>> How exactly did that example "fail"? The differences in detail hardly >>> matter; PrototypeJS trod a cow-path that ES5 paved. Most users don't worry >>> about the edge case differences. >>> >>> >>> > Your subject recalls a defunct proposal to add lexically-scoped but >>>> heap-based -- therefore object property-lookup performance hindering -- >>>> extension properties. >>>> >>>> I have to say this surprises me, a performance issue is the last thing >>>> I expected. What about attaching a prototype as a closure variable, >>>> something (and this is a syntax I __don't__ like) like: >>>> ``` >>>> (function(use Array){ >>>> Array.prototype.contains = function() { ... >>>> ... >>>> // any code here has access to .contains, code that did not >>>> originate here does not have such access, much like a closure. >>>> // other code is free to use Array without any collisions. >>>> })() >>>> ``` >>>> Again, I __don't__ like this sort of syntax and I'm __not__ sure about >>>> the semantics here, I just noticed I have this problem - I'm probably not >>>> the most qualified for coming up with the solution out of the amazing minds >>>> right here. >>>> >>>> Don't worry about syntax yet. The issue in any such semantic extension >>> is the required extra lookup parameter: not just contains on the right of >>> dot, but the enclosing closure scope. >>> >>> Unqualified identifiers (ones not used after dot) indeed require lookup >>> via closure environments, to the global (let's ignore 'with' and DOM inline >>> event handlers). >>> >>> Dot-qualified identifiers and equivalent bracketed computed property >>> name accesses require prototype chain lookup. >>> >>> No matter the syntax, and independent of details of how one specs it, >>> you're proposing a hybrid of the two schemes. This must cost, and it does >>> cost. >>> >>> /be >>> >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss@mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> >
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss