RFC -- Function.prototype.partial() -- a proposal for ECMAScript4

P

Peter Michaux

Hi,

The following doesn't work as intended because "this" refers to
"window" when the event fires.

var bert = {
name: 'Bert',
speak: function() {alert(this.name);}
};

bertDiv.addEventListener('click', bert.speak, false);

------------------

I posted to the ECMAScript4 mailing list, a casual proposal for
function support for partial application that also fixes execution
scope. With some JavaScript library you would write the above example
as this to fix the scope

bertDiv.addEventListener('click', bert.speak.bind(bert), false);

Most JavaScript libraries repeat this functionality to bind event
listener callbacks to a particular object. Dojo, Mootools, Prototype,
and MochiKit are the first four libraries I looked at and they all
implement something like this. YUI does the same thing with event
handlers but with different syntax.

------------------

Brendan Eich responded to me that he likes the idea and asked for me
to make a

"proposal for Function.partial (let's call it), a static method of
Function, whose first parameter is the callable to partially apply; as
with the static generics there would be a Function.prototype.partial
taking just the arguments and using |this| as the callable to
partially apply."

The "static generics" page:

http://wiki.ecmascript.org/doku.php?id=proposals:static_generics

-------------------

Below is my proposed functionality. Surely there are many ways to
write this in JavaScript but this would likely be implemented in C so
only the correct behavior is important here.

I've defined partialApply and partialCall because frequently I find
Function.prototype.apply functionality so useful and more general.
Brendan can take and/or leave any parts he likes, of course.


Function.partialApply = function(f, scope, argums) {
// make a local shallow copy of the argums array
var args = [];
for (var i=0; i<argums.length; i++) {
args.push(argums);
}
return function() {
for (var i=0; i<arguments.length; i++) {
args.push(arguments);
}
return f.apply(scope, args);
}
};

Function.partialCall = function(f, scope) {
// convert extra arguments to an array
// so can reuse Function.partialApply
var args = [];
for (var i=2; i<arguments.length; i++) {
args.push(arguments);
}
return Function.partialApply(f, scope, args)
};

Function.prototype.partialApply = function(scope, argums) {
return Function.partialApply(this, scope, argums);
};

Function.prototype.partialCall = function(scope) {
var args = [];
for (var i=1; i<arguments.length; i++) {
args.push(arguments);
}
return Function.partialApply(this, scope, args);
};


// example uses

function foo(a, b, c, d) {
alert(this.name + a + b + c + d);
}

var bert = {name:'Bert'};

var partiallyCalledFoo = foo.partialCall(bert, 1, 2);
partiallyCalledFoo(3, 4); // alert says "Bert1234"

var partiallyAppliedFoo = foo.partialApply(bert, [1, 2]);
partiallyAppliedFoo(3, 4); // alert says "Bert1234"

var partiallyCalledFoo = Function.partialCall(foo, bert, 1, 2);
partiallyCalledFoo(3, 4); // alert says "Bert1234"

var partiallyAppliedFoo = Function.partialApply(foo, bert, [1, 2]);
partiallyAppliedFoo(3, 4); // alert says "Bert1234"

// second partial applicaiton doesn't (and shouldn't)
// change scope of execution of the original function.
var partiallyAppliedFoo = foo.partialApply(bert, [1, 2]);
var matilda = {name:'Matilda'};
var doublelyPartiallyAppliedFoo =
partiallyAppliedFoo.partialCall(matilda, 5)
doublelyPartiallyAppliedFoo(7); // alert says "Bert1257"

-------------------------------

// in a loop is big payoff
for (var i=0; i<people.length; i++) {
var person = people;
person.div.addEventListener('click',
person.speak.bind(person, 1), false);
}

-------------------------------

// here is another common situation

function handler(position) {
alert('item ' + position + ': ' + this.innerHTML);
}
var items =
document.getElementById('myList').getElementsByTagName('li');

// instead of this mess
for (var i=0; i<items.length; i++) {
var item = items;
item.addEventListener('click', (function(item, i) {
return function(){
return handler.call(item, i);
}
})(item, i), false);
}

// we could write
for (var i=0; i<items.length; i++) {
var item = items;
item.addEventListener('click', handler.partialCall(item, i),
false);
}

-------------------------------

Naturally, I believe c.l.j readers are the best group from which to
solicit well-considered comments before I go ahead and make a proposal
to screw up JavaScript :)

Thanks,
Peter
 
D

David Golightly

Hi,

The following doesn't work as intended because "this" refers to
"window" when the event fires.

var bert = {
name: 'Bert',
speak: function() {alert(this.name);}
};

bertDiv.addEventListener('click', bert.speak, false);

------------------

I posted to the ECMAScript4 mailing list, a casual proposal for
function support for partial application that also fixes execution
scope. With some JavaScript library you would write the above example
as this to fix the scope

bertDiv.addEventListener('click', bert.speak.bind(bert), false);

Most JavaScript libraries repeat this functionality to bind event
listener callbacks to a particular object. Dojo, Mootools, Prototype,
and MochiKit are the first four libraries I looked at and they all
implement something like this. YUI does the same thing with event
handlers but with different syntax.

------------------

Brendan Eich responded to me that he likes the idea and asked for me
to make a

"proposal for Function.partial (let's call it), a static method of
Function, whose first parameter is the callable to partially apply; as
with the static generics there would be a Function.prototype.partial
taking just the arguments and using |this| as the callable to
partially apply."

The "static generics" page:

http://wiki.ecmascript.org/doku.php?id=proposals:static_generics

-------------------

Below is my proposed functionality. Surely there are many ways to
write this in JavaScript but this would likely be implemented in C so
only the correct behavior is important here.

I've defined partialApply and partialCall because frequently I find
Function.prototype.apply functionality so useful and more general.
Brendan can take and/or leave any parts he likes, of course.

Function.partialApply = function(f, scope, argums) {
// make a local shallow copy of the argums array
var args = [];
for (var i=0; i<argums.length; i++) {
args.push(argums);
}
return function() {
for (var i=0; i<arguments.length; i++) {
args.push(arguments);
}
return f.apply(scope, args);
}
};

Function.partialCall = function(f, scope) {
// convert extra arguments to an array
// so can reuse Function.partialApply
var args = [];
for (var i=2; i<arguments.length; i++) {
args.push(arguments);
}
return Function.partialApply(f, scope, args)
};

Function.prototype.partialApply = function(scope, argums) {
return Function.partialApply(this, scope, argums);
};

Function.prototype.partialCall = function(scope) {
var args = [];
for (var i=1; i<arguments.length; i++) {
args.push(arguments);
}
return Function.partialApply(this, scope, args);
};

// example uses

function foo(a, b, c, d) {
alert(this.name + a + b + c + d);
}

var bert = {name:'Bert'};

var partiallyCalledFoo = foo.partialCall(bert, 1, 2);
partiallyCalledFoo(3, 4); // alert says "Bert1234"

var partiallyAppliedFoo = foo.partialApply(bert, [1, 2]);
partiallyAppliedFoo(3, 4); // alert says "Bert1234"

var partiallyCalledFoo = Function.partialCall(foo, bert, 1, 2);
partiallyCalledFoo(3, 4); // alert says "Bert1234"

var partiallyAppliedFoo = Function.partialApply(foo, bert, [1, 2]);
partiallyAppliedFoo(3, 4); // alert says "Bert1234"

// second partial applicaiton doesn't (and shouldn't)
// change scope of execution of the original function.
var partiallyAppliedFoo = foo.partialApply(bert, [1, 2]);
var matilda = {name:'Matilda'};
var doublelyPartiallyAppliedFoo =
partiallyAppliedFoo.partialCall(matilda, 5)
doublelyPartiallyAppliedFoo(7); // alert says "Bert1257"

-------------------------------

// in a loop is big payoff
for (var i=0; i<people.length; i++) {
var person = people;
person.div.addEventListener('click',
person.speak.bind(person, 1), false);
}

-------------------------------

// here is another common situation

function handler(position) {
alert('item ' + position + ': ' + this.innerHTML);
}
var items =
document.getElementById('myList').getElementsByTagName('li');

// instead of this mess
for (var i=0; i<items.length; i++) {
var item = items;
item.addEventListener('click', (function(item, i) {
return function(){
return handler.call(item, i);
}
})(item, i), false);
}

// we could write
for (var i=0; i<items.length; i++) {
var item = items;
item.addEventListener('click', handler.partialCall(item, i),
false);
}

-------------------------------

Naturally, I believe c.l.j readers are the best group from which to
solicit well-considered comments before I go ahead and make a proposal
to screw up JavaScript :)

Thanks,
Peter


I typically keep a method around in my toolkit like this:

function createClosure(func, context) {
context = context || func;
var args = [].slice.call(arguments, 1);
return function () {
args = args.concat([].slice.call(arguments));
func.apply(context, args);
};
}

used in your context:

function test() { return 'hello, '+[].join.call(arguments, ','); }

var partiallyCalled = createClosure(test, null, 1, 2);

partiallyCalled(3, 4); // => hello, 1, 2, 3, 4

This functional programming stuff is nice-to-have but implementing it
yourself as-needed is also trivial, so I don't feel that I'm clamoring
for it. I would like to get a sense, though, of how much optimization
is really possible by moving this into machine code vs. interpreted
code. My hunch is, since we're dealing with arguments collections,
we're looking at very small iteration lengths and thus not much speed
gain. However, I may be wrong here if I see a good use case to the
contrary. I'd much rather see the JS 1.6 Array extras moved into
ECMA4.

-David
 
P

Peter Michaux

I typically keep a method around in my toolkit like this:

function createClosure(func, context) {
context = context || func;
var args = [].slice.call(arguments, 1);

That is a fancy trick.

I believe the arguments object is going to become a full Array
instance. However if it wasn't but the generics arrive then I believe
you could write

var args = Array.slice(arguments, 1);

since arguments is an array-like object.


return function () {
args = args.concat([].slice.call(arguments));
func.apply(context, args);
};

}

used in your context:

function test() { return 'hello, '+[].join.call(arguments, ','); }

var partiallyCalled = createClosure(test, null, 1, 2);

partiallyCalled(3, 4); // => hello, 1, 2, 3, 4

This functional programming stuff is nice-to-have but implementing it
yourself as-needed is also trivial, so I don't feel that I'm clamoring
for it.

Agreed. It isn't essential. Lisp can be boiled down to something like
7 functions and the user can implement the rest. That doesn't sound
convenient :)

arr[arr.length] = 1;

// vs.

arr.push(1);

// ------------

obj._$f$_ = func;
obj._$f$_(1, 2, 3);
delete obj._$f$_;

// vs.

func.apply(obj, [1, 2, 3]);

// vs.

func.call(obj, 1, 2, 3);


Having common idioms become part of the language is convenient.

Fixing scope is something that developers need to do all the time.
This frequency indicates JavaScript itself makes this a useful (or
somewhat necessary) capability and so would be a nice complement to
the language itself for completeness.

Also imagine the bandwidth saved on the Internet as a whole if so many
people didn't have to serve the equivalent of createClosure. This is
more of a point of interest for me but it is interesting.

I would like to get a sense, though, of how much optimization
is really possible by moving this into machine code vs. interpreted
code. My hunch is, since we're dealing with arguments collections,
we're looking at very small iteration lengths and thus not much speed
gain. However, I may be wrong here if I see a good use case to the
contrary. I'd much rather see the JS 1.6 Array extras moved into
ECMA4.

Thankfully this isn't an either or situation. It could be both.

I didn't know the array extras were not in ECMAScript 4. If they are
not you could speak up on the ECMAScript4 mailing list.

Peter
 
T

Thomas 'PointedEars' Lahn

Peter said:
I typically keep a method around in my toolkit like this:

function createClosure(func, context) {
context = context || func;
var args = [].slice.call(arguments, 1);

That is a fancy trick.

Creating a new Array object is only needed here because the author
does not understand what he is doing.
I believe the arguments object is going to become a full Array
instance. However if it wasn't but the generics arrive then I
believe you could write

var args = Array.slice(arguments, 1);

since arguments is an array-like object.

No, because slice() is not a method of the Array constructor, but of
the Array prototype object. Therefore,

var args = Array.prototype.slice.call(arguments, 1);

works.


PointedEars
 
D

David Golightly

Peter said:
I typically keep a method around in my toolkit like this:
function createClosure(func, context) {
context = context || func;
var args = [].slice.call(arguments, 1);
That is a fancy trick.

Creating a new Array object is only needed here because the author
does not understand what he is doing.

Of course, I could have used Array.prototype.slice.call, but creating
a new Array object here is so cheap that saving that many characters
in typing was worth the expense. Save your assumptions for yourself.
No, because slice() is not a method of the Array constructor, but of
the Array prototype object. Therefore,

var args = Array.prototype.slice.call(arguments, 1);

works.

If you bothered to read the context of Peter's post, you would
understand he's talking in the hypothetical context of ECMA 4, should
this language feature be adopted there. See
http://developer.mozilla.org/en/docs/New_in_JavaScript_1.6#Array_and_String_generics
for an example of how this works in JS 1.6 (as implemented in FireFox
1.5+).

-David
 
D

David Golightly

Peter said:
I typically keep a method around in my toolkit like this:
function createClosure(func, context) {
context = context || func;
var args = [].slice.call(arguments, 1);
That is a fancy trick.
Creating a new Array object is only needed here because the author
does not understand what he is doing.

Of course, I could have used Array.prototype.slice.call, but creating
a new Array object here is so cheap that saving that many characters
in typing was worth the expense. Save your assumptions for yourself.

Granted, according to my ad-hoc benchmarks, Array.prototype.slice.call
takes about 1/5th the execution time that [].slice.call does. But
we're still on the order of 0.1ms per execution, so the readability
tradeoff is often worth it for me. However, a utility function like
this deserves this optimization.
 
D

David Golightly

This functional programming stuff is nice-to-have but implementing it
yourself as-needed is also trivial, so I don't feel that I'm clamoring
for it.

Agreed. It isn't essential. Lisp can be boiled down to something like
7 functions and the user can implement the rest. That doesn't sound
convenient :)

arr[arr.length] = 1;

// vs.

arr.push(1);

// ------------

obj._$f$_ = func;
obj._$f$_(1, 2, 3);
delete obj._$f$_;

// vs.

func.apply(obj, [1, 2, 3]);

// vs.

func.call(obj, 1, 2, 3);

Having common idioms become part of the language is convenient.

Fixing scope is something that developers need to do all the time.
This frequency indicates JavaScript itself makes this a useful (or
somewhat necessary) capability and so would be a nice complement to
the language itself for completeness.

I agree. I often find myself wishing JS came with more "batteries
included", to borrow a Python phrase - especially since managing scope
can be one of the most labor-intensive processes in doing extensive
JavaScript work, especially in a browser environment with event-driven
UI, closure memory leak pitfalls, and asynchronous callbacks. Current
implementations of JS 1.6-1.8 suggest I'm not alone. And the upcoming
ECMA 4 spec looks promising as well - I just hope the functional style
is properly represented there to offset the potential for ActionScript/
Java-style classical inheritance bloat.
Also imagine the bandwidth saved on the Internet as a whole if so many
people didn't have to serve the equivalent of createClosure. This is
more of a point of interest for me but it is interesting.

Hm, the bandwidth of 8 lines of code seems negligible; I would rather
spend my time lobbying UA manufacturers to implement a native
getElementsBySelector, which will save a HUGE amount of bandwidth.
Thankfully this isn't an either or situation. It could be both.

I didn't know the array extras were not in ECMAScript 4. If they are
not you could speak up on the ECMAScript4 mailing list.

Yeah, unfortunately they don't appear in the spec so far:

http://developer.mozilla.org/es4/spec/chapter_19_native_objects.html#array_objects

though, thanks to your suggestion, I've signed up for the mailing list
and will be asking about it shortly.

-David
 
P

Peter Michaux

R

Richard Cornford

Peter said:
The following doesn't work as intended because "this"
refers to "window" when the event fires.

That makes a huge assumption about the intention of its author. If it
were written by someone who understood javascript, and so understood
that the - this - value is determined by how a function is called, that
the arguments to a function call are resolved to values prior to the
call, and that the - this - value in a function used with the DOM -
addEventListener - of a Node will be a reference to the Node (not the
'window') then that author's intention would be precisely what the code
would do.
var bert = {
name: 'Bert',
speak: function() {alert(this.name);}
};

bertDiv.addEventListener('click', bert.speak, false);

------------------

I posted to the ECMAScript4 mailing list, a casual proposal
for function support for partial application that also fixes
execution scope.

"Execution scope"? You want a facility for dynamically playing with
scope chains beyond what is already available with the - with -
statement? Seems an odd desire given that the - with - statement is
already subject to justifiable criticism for the
non-obvious/counterintuitive possibilities its existence introduces into
the language.

Or is it the case that when you say "scope" you are actually referring
to something that has nothing to do with javascript's lexical and static
scope?
With some JavaScript library you would write the above example
as this to fix the scope

bertDiv.addEventListener('click', bert.speak.bind(bert), false);

Maybe "with some JavaScript library", but in real javascript the author
may have anticipated the need for an event handler to be able to refer
to an object instance by means other than the - this - value and
implemented that in the object instantiation code.

And in reality 'with some JavaScript libraries' we see this 'binding'
being done at the point of calling functions/methods where the same
function/method is being bound to the same object instance over and over
again, with all of the overheads that implies. When taking a step back
and looking at the demands of the system should have made it obvious
that the 'binding' only needed to be done once.

And then again, 'with some other JavaScript' libraries' we see this
'binding' being done at the point of calling functions/methods where the
same function/method is being bound to the same object instance over and
over again, with all of the overheads that implies. When there was never
a good reason for breaking the association of an object instance from
its method properties in the first place. so, for example, in almost all
cases where some attempt has been made to emulate "named arguments" by
having each function/method call wrap its 'arguments' in an object
literal, and then use the properties of that object as arguments, an
alternative design might specify the argument to the function/method as
being an object that implements a defined 'interface' where properties
of that object defined on the interface where either null/undefined or a
method to be used as the call back. A hypothetical:-

SomeAjaxObj.callMethod(
{url:'http:/ ... ',
if200:eek:bj.sucess.bind(obj.sucess),
if404:eek:bj.notFound.bind(obj.notFound),
method:'POST', data:eek:bj.getPostData()
}
);

- call becomes a possible:-

SomeAjaxObj.callMethod(obj);

- and the - obj - object itself has the 'if200', 'if404', 'method',
'url' and 'data' properties/getters. Internally the - callMethod - holds
on to its - obj - reference and calls any call-back functions directly
on that object reference, with the implied 'correct' assignment to -
this -.

And then again, again, 'with some other JavaScript' libraries' we see
this 'binding' being done at the point of calling functions/methods
where the same function/method is being bound to the same object
instance over and over again, and for multiple arguments, with all of
the overheads that implies. Where the whole process could be internally
handled (and optionally handled), and for just the methods that need to
be bound rather and all methods used as arguments. Again, when using
wrapping arguments in an object literal to emulate "named arguments" you
could pass in the 'method' functions as raw values and have an optional
'objectToBindToAtCallBack' named argument. And the internal code could
'bind' the call-back function it used to this object prior to calling it
(or not when the argument was not provided). Avoiding the need to 'bind'
an object to any of the other possible call-back function arguments, and
keeping the details away from the library's 'users'.

Design possibilities wise, that is just the tip of the iceberg. So if
you find 'popular' libraries migrating to a particular pattern of
'binding' you should not take that as any indication that that pattern
is in any sense optimal or even good, especially when manifestations of
its use are self-evidently stupidly inefficient. It may just be that the
authors of these libraries tend to paint themselves into the same
corners and then look to each other for ways of getting themselves out
again, lacking the knowledge and/or imagination to see either
alternatives, or the design strategies that would have avoided getting
into the situation in the first place.
Most JavaScript libraries repeat this functionality to bind
event listener callbacks to a particular object. Dojo,
Mootools, Prototype, and MochiKit are the first four libraries
I looked at and they all implement something like this. YUI
does the same thing with event handlers but with different syntax.

I don't rally want to write this, but here goes: From what perspective
does Brendan Eich "like" this idea? Is it from the perspective of
someone who writes non-trivial cross-browser scripts (has anyone seen
any evidence that he has ever attempted such a thing), or from the
perspective of someone interested in the creation of a capable
interpreter/complier?

Over the years the "warnings" (potentially) issued in the javascript
console on Mozilla/Gecko browsers have included the extremely spurious,
(in ECMA 262 terms) factually false, and sometimes contrary to good
cross-browser authoring practices. And while over the years many of
these have been removed/corrected (possibly all by now, I would not know
as I don't bother displaying them at all, given there dubious history)
somebody put them there to start with, and presumably somebody closely
connected with the authoring of the javascript engine.
and asked for me to make a

"proposal for Function.partial (let's call it), a static method
of Function, whose first parameter is the callable to partially
apply; as with the static generics there would be a
Function.prototype.partial taking just the arguments and using
|this| as the callable to partially apply."

While partial evaluation, and the handling of potential arguments at the
two stages of the operation, may come into the picture, the most
significant application here is the setting of the - this - value in a
function call to a reference to a particular object instance. In which
case should it actually be the - Function - constructor and its -
prototype - that are the subject here?

Why not an instance method of Object? I.E. something like:-

obj.boundMethod = obj.alwaysCallWithThis(function(){ .... });

- where - alwaysCallWithThis - is a method of Object.prototype that
takes a function argument and retunes a function object that, when
called, calls the original function setting the - this - value to the -
this - value that existed in the - alwaysCallWithThis - method call.

We don't see that sort of implementation in existing libraries, but that
is because extending the Object.prototype in javascript code would add
an enumerable property (and may mess up for-in use), but if we are
discussing a language modification that is not a significant factor as
such a language-defined modification to Object.prototype can be marked
as non-enumerable and so be no more problematic than
Object.prototype.toString.

Below is my proposed functionality. Surely there are many
ways to write this in JavaScript but this would likely be
implemented in C so only the correct behavior is important
here.

I've defined partialApply and partialCall because frequently
I find Function.prototype.apply functionality so useful and
more general. Brendan can take and/or leave any parts he
likes, of course.


Function.partialApply = function(f, scope, argums) {
<snip> ^^^^^

"Scope" is absolutely the wrong name for this argument. Nothing you are
doing here is changing the scope (the scope of the execution context
when it is called or the [[Scope]] property of the function itself) of -
f - in any way. All that is being done is ensuring that - f - is called
with a particular - this - value.

Naturally, I believe c.l.j readers are the best group from
which to solicit well-considered comments before I go ahead
and make a proposal to screw up JavaScript :)

Well, I don't see the point in doing this at all. The fact that you can
define this is ECMA 262, 3rd Ed. code alone says that it is not
something that cannot already be done when it is necessary. Granted it
would be more efficiently if done with native code rather than
javascript, but when the need for that speed is only the consequence of
the questionable design decisions in dubious libraries resulting in
'binding' being done inefficiently in application code then that is
hardly a justification.

On the other hand, if implemented the result would be harmless, and may
even be occasionally useful, some time in the next decade when (any)
ECMA 262 4th Ed. has existed long enough to be consistently available in
web browsers.

Richard.
 
R

Richard Cornford

David said:
Peter Michaux wrote:
On Aug 31, 5:31 pm, David Golightly wrote:
I typically keep a method around in my toolkit like this:
function createClosure(func, context) {
context = context || func;
var args = [].slice.call(arguments, 1);
That is a fancy trick.
Creating a new Array object is only needed here because the
author does not understand what he is doing.

Of course, I could have used Array.prototype.slice.call, but
creating a new Array object here is so cheap that saving that
many characters in typing was worth the expense. Save your
assumptions for yourself.

Granted, according to my ad-hoc benchmarks,
Array.prototype.slice.call takes about 1/5th the execution time
that [].slice.call does. But we're still on the order of 0.1ms
per execution, so the readability tradeoff is often worth it for
me.
<snip>

I though you just wrote that it was a typing trade-off. If it were
readability trade-off (or at least the comprehension of what is being
read) the - Array.prototype.slice.call - would seem the better option,
as it is explicit about what is being used/done.

Richard.
 
J

John G Harris

Hi,

The following doesn't work as intended because "this" refers to
"window" when the event fires.

var bert = {
name: 'Bert',
speak: function() {alert(this.name);}
};

bertDiv.addEventListener('click', bert.speak, false);
<snip>

Surely "intended" is the wrong word there in the first sentence. Surely
no-one expected 'this' to find out which property of which object a
function object is the value of. For a start, what if it's the value of
several properties, of several objects?

John
 
D

David Golightly

While partial evaluation, and the handling of potential arguments at the
two stages of the operation, may come into the picture, the most
significant application here is the setting of the - this - value in a
function call to a reference to a particular object instance. In which
case should it actually be the - Function - constructor and its -
prototype - that are the subject here?

Actually, when it comes down to it, binding methods to any objects
other than a function's -prototype- object for the sake of using the -
this- keyword to refer to that object in the function's scope is
largely unnecessary, since the same effect can always be achieved by
passing in the object in question as an additional argument instead.
I believe the motivation for doing so is not to achieve something that
is not otherwise possible, but to allow a use of syntactic sugar that
embodies a developer's conception of the context at hand. Whatever
that may be. Regardless, it's a technique that's available to all but
need not be used by all.
Why not an instance method of Object? I.E. something like:-

obj.boundMethod = obj.alwaysCallWithThis(function(){ .... });

- where - alwaysCallWithThis - is a method of Object.prototype that
takes a function argument and retunes a function object that, when
called, calls the original function setting the - this - value to the -
this - value that existed in the - alwaysCallWithThis - method call.

We don't see that sort of implementation in existing libraries, but that
is because extending the Object.prototype in javascript code would add
an enumerable property (and may mess up for-in use), but if we are
discussing a language modification that is not a significant factor as
such a language-defined modification to Object.prototype can be marked
as non-enumerable and so be no more problematic than
Object.prototype.toString.

In fact, the draft ECMA 4 spec includes a method -
propertyIsEnumerable - that allows binding of non-enumerable
properties to any Object's prototype, including Object itself. See:

http://wiki.ecmascript.org/doku.php?id=spec:chapter_19_native_objects#object_objects

-David
 
R

Richard Cornford

David said:
Actually, when it comes down to it, binding methods to any
objects other than a function's -prototype- object for the sake
of using the - this- keyword to refer to that object in the
function's scope is largely unnecessary,

Of course it is unnecessary. It is also unnecessary to attach the
facility to the Function prototype (it could be a global function).
Strictly it is unnecessary to do that at all.
since the same effect can always be achieved by
passing in the object in question as an additional argument
instead. I believe the motivation for doing so is not to
achieve something that is not otherwise possible,

Obviously not, as it demonstrably is possible now.
but to allow a use of syntactic sugar that
embodies a developer's conception of the context at hand.

Precisely. The alternatives are to have a global function (or maybe
static method) that effectively says "take a function and an object
instance and 'bind' the function to the object", to have a function
method that says "take that object instance and 'bind' me to it", or to
have a method of all objects that says "take that function and 'bind' it
to me". One of those best "embodies a developer's conception of the
context at hand", but whether it is the second or the third is
debatable. Current habit may be choosing the second, but that is a
decision that is being influenced by factors that are irrelevant in this
context.
Whatever that may be. Regardless, it's a technique that's
available to all but need not be used by all.


In fact, the draft ECMA 4 spec includes a method -
propertyIsEnumerable - that allows binding of non-enumerable
properties to any Object's prototype, including Object itself.

Whether, whenever it eventually shows up, the 4th edition of ECMA 262
allows properties to be declared non-enumerable or not has no bearing on
how the inability to do so at present may be impacting on the design
decisions made in current library code designs.

Richard.
 
T

Thomas 'PointedEars' Lahn

David said:
Peter Michaux wrote:
I typically keep a method around in my toolkit like this:
function createClosure(func, context) {
context = context || func;
var args = [].slice.call(arguments, 1);
That is a fancy trick.
Creating a new Array object is only needed here because the author
does not understand what he is doing.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Of course, I could have used Array.prototype.slice.call, but creating
a new Array object here is so cheap that saving that many characters
in typing was worth the expense. Save your assumptions for yourself.

Granted, according to my ad-hoc benchmarks, Array.prototype.slice.call
takes about 1/5th the execution time that [].slice.call does. But
we're still on the order of 0.1ms per execution, so the readability
tradeoff is often worth it for me. However, a utility function like
this deserves this optimization.

q.e.d.


PointedEars
 
D

dhtmlkitchen

Hi,

The following doesn't work as intended because "this" refers to
"window" when the event fires.

var bert = {
name: 'Bert',
speak: function() {alert(this.name);}
};

bertDiv.addEventListener('click', bert.speak, false);

------------------

I posted to the ECMAScript4 mailing list, a casual proposal for
function support for partial application that also fixes execution
scope. With some JavaScript library you would write the above example
as this to fix the scope

bertDiv.addEventListener('click', bert.speak.bind(bert), false);

Most JavaScript libraries repeat this functionality to bind event
listener callbacks to a particular object. Dojo, Mootools, Prototype,
and MochiKit are the first four libraries I looked at and they all
implement something like this. YUI does the same thing with event
handlers but with different syntax.

------------------

Brendan Eich responded to me that he likes the idea and asked for me
to make a

"proposal for Function.partial (let's call it), a static method of
Function, whose first parameter is the callable to partially apply; as
with the static generics there would be a Function.prototype.partial
taking just the arguments and using |this| as the callable to
partially apply."

The "static generics" page:

http://wiki.ecmascript.org/doku.php?id=proposals:static_generics

-------------------

Below is my proposed functionality. Surely there are many ways to
write this in JavaScript but this would likely be implemented in C so
only the correct behavior is important here.

I've defined partialApply and partialCall because frequently I find
Function.prototype.apply functionality so useful and more general.
Brendan can take and/or leave any parts he likes, of course.

Function.partialApply = function(f, scope, argums) {
// make a local shallow copy of the argums array
var args = [];
for (var i=0; i<argums.length; i++) {
args.push(argums);
}
return function() {
for (var i=0; i<arguments.length; i++) {
args.push(arguments);
}
return f.apply(scope, args);
}
};

Function.partialCall = function(f, scope) {
// convert extra arguments to an array
// so can reuse Function.partialApply
var args = [];
for (var i=2; i<arguments.length; i++) {
args.push(arguments);
}
return Function.partialApply(f, scope, args)
};

Function.prototype.partialApply = function(scope, argums) {
return Function.partialApply(this, scope, argums);
};

Function.prototype.partialCall = function(scope) {
var args = [];
for (var i=1; i<arguments.length; i++) {
args.push(arguments);
}
return Function.partialApply(this, scope, args);
};

// example uses

function foo(a, b, c, d) {
alert(this.name + a + b + c + d);
}

var bert = {name:'Bert'};

var partiallyCalledFoo = foo.partialCall(bert, 1, 2);
partiallyCalledFoo(3, 4); // alert says "Bert1234"

var partiallyAppliedFoo = foo.partialApply(bert, [1, 2]);
partiallyAppliedFoo(3, 4); // alert says "Bert1234"

var partiallyCalledFoo = Function.partialCall(foo, bert, 1, 2);
partiallyCalledFoo(3, 4); // alert says "Bert1234"

var partiallyAppliedFoo = Function.partialApply(foo, bert, [1, 2]);
partiallyAppliedFoo(3, 4); // alert says "Bert1234"

// second partial applicaiton doesn't (and shouldn't)
// change scope of execution of the original function.
var partiallyAppliedFoo = foo.partialApply(bert, [1, 2]);
var matilda = {name:'Matilda'};
var doublelyPartiallyAppliedFoo =
partiallyAppliedFoo.partialCall(matilda, 5)
doublelyPartiallyAppliedFoo(7); // alert says "Bert1257"

-------------------------------

// in a loop is big payoff
for (var i=0; i<people.length; i++) {
var person = people;
person.div.addEventListener('click',
person.speak.bind(person, 1), false);
}

-------------------------------

// here is another common situation

function handler(position) {
alert('item ' + position + ': ' + this.innerHTML);
}
var items =
document.getElementById('myList').getElementsByTagName('li');

// instead of this mess
for (var i=0; i<items.length; i++) {
var item = items;
item.addEventListener('click', (function(item, i) {
return function(){
return handler.call(item, i);
}
})(item, i), false);
}

// we could write
for (var i=0; i<items.length; i++) {
var item = items;
item.addEventListener('click', handler.partialCall(item, i),
false);
}


You're not selling me on that example.

The above code can and should be replaced with one event handler on
the myList, then catch the bubbled event.

Some useful applications of this might be a
* pub-sub event registry
* an animation lib

The problem is that methods in ES3 are not bound to their objects.

So something as trivial as an object starting an animation on itself,
the thisVal gets changed to window.

BerfWidget.prototype = {
startAnim : function() {
// broken.
// setInterval(this.anim, 10);
// fixed:
setInterval("BerfWidget.instances[' " + this.id + "'].anim()",
10);
}

,anim : function() {
print( this );
}
};

The commented-out line prints "window", pausing 10ms between each call
to anim. It's easier to read and cleaner design, but by design of the
language, will have the result it does.

http://developer.mozilla.org/es4/spec/chapter_8_functions.html

"A function is a callable object. In general functions consist of a
block of code, a set of traits, and a list of scopes. Instance methods
are functions that also consist of a receiver object that this
references are bound to."


class Bork {

var x : int = 0;
prototype function blah() : void {
if(x <= 10 ){
print( this.x++ );
}
else {
fireBlahDone();
}
}
prototype function fireBlahDone() : void { }
}

var bork : Bork = new Bork();
var blahTimer = setInterval(bork, 100);
bork.fireBlahDone = function fireBlahDone(){
clearInterval(blahTimer);
};


Given the above, would binding functions still be valuable?

What are the tradeoffs to adding such functionality to the language?

Regarding the Ajax callbacks, I would encourage looking at the
Progress Events specification. This is a more flexible way to handle
remote callbacks than the DI approach that everyone uses nowadays
(lame/weak).

I am also promoting Progress Events to publish a "complete" event that
fires regardless whether the call was successful of failed. (call is
done, hide "loading.gif"). But that's beside the point.

Garret
 
D

dhtmlkitchen

Sorry, my example was WRONG. It states in the spec:

"The value of this in an instance method is a reference to the
instance that is associated with the method. When an instance method
is extracted from an object, a bound method is created to bind the
value of this to that host object. Assignment of the bound method to a
property of another object does not affect the binding of this. For
example,
class A {
var x
function A() { this.x = 10 }
function m() { print(this.x) }
}
var a = new A()
var o = { x : 20 }
o.m = a.m
o.m() // traces 10
"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,828
Latest member
LauraCastr

Latest Threads

Top