Scoped binding of a method to an object

Benjamin (Inglor) Gruenbaum inglor at gmail.com
Sun Oct 13 14:35:29 PDT 2013


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.seliger at 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 <
> inglor at 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 <brendan at mozilla.com>wrote:
>>
>>> Benjamin (Inglor) Gruenbaum <mailto:inglor at gmail.com>
>>>> October 13, 2013 11:00 AM
>>>>
>>>> Brendan Eich<brendan at mozilla.com <mailto:brendan at 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 at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20131014/ac9e91e3/attachment-0001.html>


More information about the es-discuss mailing list