Concise Method Binding

JD Isaacks jd at jisaacks.com
Mon Nov 30 21:04:04 UTC 2015


> I also prefer your suggestion to delegating this functionality to a
decorator; ideally the decorator would be built into the language.

I think using a decorator to get this functionality is a great way to
achieve it if it were to not be built into the language. However, I think
if it were to be built into the language, my bind operator makes more sense.

The bind operator is already being used, for 3 forms of method binding:

```
// 1
foo::bar(...args);
// equivalent to
bar.apply(foo, args);

// 2
foo::bar
// equivalent to
bar.bind(foo)

// 3
::foo.bar
// equivalent to
foo.bar.bind(foo)
```

With all these already being added in only makes my suggestion the more
natural addition. And will make code more easy to recognize at a glance.

Plus all of the existing uses of the bind operator are just syntactic sugar
for something you can already do, hence my equivalents shown above.
However there is still no way to bind a method to an
object declaratively in an object literal. Currently, you must first create
the object, then bind a method to it.


On Wed, Nov 11, 2015 at 1:00 PM, Gilbert B Garza <gilbertbgarza at gmail.com>
wrote:

> Forgive me if I'm missing the point, but isn't the entire purpose of using
> classes to make all instances share the same function in memory via `this`
> ? If you want methods to always be bound, why not use closures instead?
>
> ```js
> function Person (name) {
>   var person = this
>   person.greet = function () {
>     return person.name + " says hi!";
>   };
> }
>
> var alice = new Person('Alice');
> alice.greet() //=> "Alice says hi!";
>
> var f = alice.greet;
> f() //=> "Alice says hi!";
> ```
>
> On Wed, Nov 11, 2015 at 10:59 AM, JD Isaacks <jd at jisaacks.com> wrote:
>
>> Ahh, good point Bergi. Thanks for brining that up.
>>
>> On Wed, Nov 11, 2015 at 11:55 AM, JD Isaacks <jd at jisaacks.com> wrote:
>>
>>> I like this very much. I would prefer this to my recommendation. So how
>>> to we go about proposing it as a change to an existing proposal?
>>>
>>> On Wed, Nov 11, 2015 at 11:45 AM, Andrea Giammarchi <
>>> andrea.giammarchi at gmail.com> wrote:
>>>
>>>> The way it could work is similar to the following one:
>>>>
>>>> ```js
>>>>
>>>> (function (wm){'use strict';
>>>>
>>>>   // just to show the possible internal slot mechanism
>>>>   Object.prototype.boundTo = function (method) {
>>>>     // since I've used this for ages now in eddy.js, just replicating
>>>>     var fn = typeof method === 'function' ? method : this[method];
>>>>     var bound = wm.get(this);
>>>>     if (!bound) wm.set(this, bound = {fn:[], bound:[]});
>>>>     var i = bound.fn.indexOf(fn);
>>>>     if (i < 0) bound.bound[i = bound.fn.push(fn) - 1] = fn.bind(this);
>>>>     return bound.bound[i];
>>>>   };
>>>>
>>>> }(new WeakMap));
>>>>
>>>>
>>>> // example
>>>> var obj = {method: function () { return this; }};
>>>>
>>>> // now, whenever needed
>>>> obj.boundTo(obj.method);
>>>>
>>>> // will create the slot and set it up with obj.method
>>>> // so that the following is true
>>>> obj.boundTo(obj.method) === obj.boundTo('method') &&
>>>> obj.boundTo('method')() === obj;
>>>>
>>>> // if it's about another method
>>>> // the equivalent of this
>>>> ::obj.anotherMethod
>>>>
>>>> // whould be
>>>> obj.boundTo(anotherMethod);
>>>>
>>>> ```
>>>>
>>>> The string fallback is not needed or relevant, it's just a semantic
>>>> shortcut in my example to reach the method through the object without
>>>> repeating the object name
>>>>
>>>> Regards
>>>>
>>>>
>>>>
>>>>
>>>> On Wed, Nov 11, 2015 at 4:23 PM, JD Isaacks <jd at jisaacks.com> wrote:
>>>>
>>>>> Yes your point of view is more clear now, I like this is a lot.
>>>>>
>>>>> But I do not know how that would be transpiled or what the desugared
>>>>> version would look like. However, that would be awesome as you described.
>>>>>
>>>>> A thing to note. You keep using `obj::method` which is different from
>>>>> `::object.method` the former is when method is not already attached to the
>>>>> object, the later is for then it is.
>>>>>
>>>>> An example:
>>>>>
>>>>> ```
>>>>> let foo = function(){};
>>>>> let bar = {};
>>>>>
>>>>> bar::foo // foo.bind(bar);
>>>>> ```
>>>>>
>>>>> verses
>>>>>
>>>>> ```
>>>>> let bar = { foo(){} };
>>>>>
>>>>> ::foo.bar // foo.bar.bind(foo);
>>>>> ```
>>>>>
>>>>> I think both cases theoretically would be awesome to work as you
>>>>> described. Just fuzzy on how it would look underneath.
>>>>>
>>>>> On Wed, Nov 11, 2015 at 11:14 AM, Andrea Giammarchi <
>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>
>>>>>> Yeah, I've got that, my point is that whenever you need it you just
>>>>>> `obj::method`
>>>>>>
>>>>>> Your example indeed says that currently the proposal is that
>>>>>> `obj::method` is similar to `obj.method.bind(obj)` which is indeed always
>>>>>> different and indeed you want something that makes method always the
>>>>>> same/unique bound one, which I believe is universally the preferred way.
>>>>>>
>>>>>> What are two different bound of the same method useful for? Pretty
>>>>>> much nothing, IMHO, while having a shortcut to lazily obtain a single bound
>>>>>> version of that method for that object can be useful in many ways, as
>>>>>> example `obj.on('event', anotherObj::method)` where it's always possible at
>>>>>> that point to `obj.removeListener('event', anotherObj::method)` in case its
>>>>>> needed.
>>>>>>
>>>>>> Having a shortcut that all it does is replace something already short
>>>>>> to write like a `.bind` feels to me like a missed opportunity.
>>>>>>
>>>>>> Moreover, with this improvement you won't need/care to have
>>>>>> self-bound methods at all
>>>>>>
>>>>>> ```js
>>>>>> let obj = { method(){} };
>>>>>>
>>>>>> // and whenever needed you use
>>>>>> obj::method;
>>>>>> ```
>>>>>>
>>>>>> Hope my POV is more clear now.
>>>>>>
>>>>>> Regards
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Wed, Nov 11, 2015 at 4:01 PM, JD Isaacks <jd at jisaacks.com> wrote:
>>>>>>
>>>>>>> I think what you are suggesting already exists with `::obj.method`
>>>>>>> which evaluates to `obj.method.bind(obj)`
>>>>>>>
>>>>>>> However, this creates a new function each time so `::obj.method
>>>>>>> !== ::obj.method`, not sure how `::obj.method === ::obj.method` would work.
>>>>>>>
>>>>>>> I sort of agree with you that using it that way would be preferred.
>>>>>>> However if the community wants bound methods attached to objects, there is
>>>>>>> currently no way to do that with an object literal.
>>>>>>>
>>>>>>> You would have to do something like:
>>>>>>>
>>>>>>> ```
>>>>>>> let obj = {};
>>>>>>> obj.method = function(){}.bind(obj);
>>>>>>> ```
>>>>>>>
>>>>>>> With my proposal you can.
>>>>>>>
>>>>>>> ```
>>>>>>> let obj = { ::method(){} };
>>>>>>> ```
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Wed, Nov 11, 2015 at 10:20 AM, Andrea Giammarchi <
>>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>>
>>>>>>>> Just my thoughts, I wouldn't put any self-bound thing in the class
>>>>>>>> and rather improve that `::` proposal so that whenever you `obj::method` it
>>>>>>>> creates a uniquely bound callback so that `obj::method === obj::method` and
>>>>>>>> at that point whenever you need to export, pass, or use such method you
>>>>>>>> just `obj::method` or `obj::method()` or `let method = obj::method` and
>>>>>>>> bring the pattern whenever it's needed instead of being slightly different
>>>>>>>> per each "place" (class rather than objects)
>>>>>>>>
>>>>>>>> That would make it lazy, usable for events (in order to be able to
>>>>>>>> also remove them) and easily transpilable for smoother migration.
>>>>>>>>
>>>>>>>> Having `class A { ::method() {} }` feels like somebody is playing
>>>>>>>> too much with the protoype or "accidentally" polluting the constructor
>>>>>>>>
>>>>>>>> Regards
>>>>>>>>
>>>>>>>>
>>>>>>>> On Wed, Nov 11, 2015 at 2:50 PM, JD Isaacks <jd at jisaacks.com>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> Andrea, Sort of. I am talking about adding an additional place
>>>>>>>>> where that operator `::` can be used -- with concise methods.
>>>>>>>>>
>>>>>>>>> Currently they cannot be used in the way I described above but I
>>>>>>>>> think there are several reasons why it makes sense.
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> es-discuss mailing list
>>>>>>>>> es-discuss at mozilla.org
>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>> _______________________________________________
>> 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/20151130/f8ee4dc0/attachment-0001.html>


More information about the es-discuss mailing list