Self-”partially applying” JavaScript functions
Was: self-currying JavaScript functions
I read this nice post on self-currying JavaScript functions, and even though the code to me is not optimal (dispite the low line count), it is improperly named, and it depends on the Prototype JavaScript library (which I really don’t like), it is a very nice script and a very nice idea. The trick in this script is using Function.prototype.length. I didn’t know that this property existed, but after digging a bit I’ve realized, that it has been in ECMAScript at least since 3rd edition (which is the latest edition published in 1999), in JavaScript since v1.1, but only made it into ActionScript by ActionScript 3 (which I haven’t study in as much detail as I have with ActionScript 1 and 2 in relation to my book on basic programming in these versions).
In this post I discuss this property and functionality a bit further, and I implement this function for creating self-”partially applying” functions using both no framework, the MochiKit framework and the Prototype framework.
Background
So, what is this property? I have not seen anyone use it before, not in production nor in any of the major JavaScript libraries. It might have been in use by a lot of people several times, but I just haven’t come across it. It has the simple function of returning the number of named arguments, that a given function is originally created with. The function will be called and might work just fine given less or more parameters, but Function.prototype.length is the number of named arguments in the definition. The ECMAScript language specification is kind of vague on the functionality, as it uses the term “usually”:
The value of the
lengthproperty is usually an integer that indicates the “typical” number of arguments expected by the function. However, the language permits the function to be invoked with some other number of arguments. The behaviour of a function when invoked on a number of arguments other than the number specified by itslengthproperty depends on the function. […]
In his post James Coglan uses this property to create what he originally denotes as self-currying functions, but agrees with a commenter, that it is in fact self-”partially applied” functions using the proper terms. I would though go to the extend to say, that the functions are neither curried nor partially applied – their application/evaluation/invocation is just postponed until the correct amount of parameters have been accumulated. If the function was partially applied, the partially applied function would run faster (in theory), as it has been specialized with respect to the already supplied parameters, but this is not the case. The parameters are simply stored until the number of parameters given (potentially across several calls) matches the number of arguments “typically” accepted by the original function.
One of the issues about the implementation by James Coglan that caught my eye, is the use of the prototype chain. Many have an opinion about whether to contaminate the prototype chain or not, but I am of the latter school and really dislike this. Contaminating the global namespace (i.e. window) is thus the only other alternative, but for this a single global object containing all library functions can be created. This is the approach that my preferred library, MochiKit, uses but Prototype (which is way more popular than MochiKit) extends built-in JavaScript objects using the prototype chain. I have thus decided to implement this functionality both in native JavaScript and using MochiKit or Prototype methodologies. Another minor issue with the implementation by Coglan is the use of the activation object to read variables from the inner function. This tends to leak memory (as collected by Quirksmode here), so the general rule of thumb here is to store such values on the function instance and retrieve them from arguments.callee.
In native JavaScript
First the implementation in native JavaScript. Note the two helper functions, of which the first is needed, as arguments isn’t a real array, and the latter is the general “curry” or “partial” method found in most libraries:
- function makeArray(a) {
- for (var b = [], i = 0; i < a.length; i++)
- b.push(a[i]);
- return b;
- }
- function bind(f, a) {
- var g = function() {
- var c = arguments.callee;
- return c._func.apply(
- null,
- c._args.concat(makeArray(arguments))
- );
- }
- g._func = f;
- g._args = a ? makeArray(a) : [];
- return g;
- }
- function partialize(f, n) {
- var g = function() {
- var c = arguments.callee;
- if (c._len <= arguments.length)
- return c._func.apply(null, arguments);
- return bind(c, arguments);
- }
- g._len = n || f.length;
- g._func = f;
- return g;
- }
The above bind-function is not optimal, as re-binding creates an extra layer of function calls which could easily be avoided by reusing the values stored on the function instance, but for this use, the above suffices.
This function can the be utilized exactly like the one by Coglan – except that this partialize function is actually a function, where the toSelfCurrying function by Coglan is a method (available through any function instance):
- var adder = function(a,b,c) {
- return a + b + c;
- };
- var add = partialize(adder);
- add(1)(2)(3) // --> 6
- add(7,8)(23) // --> 38
In MochiKit
Implementing this in MochiKit and using the power of the built-in functions (especially bind), this becomes only the last function:
- function partialize(f, n) {
- var g = function() {
- var c = arguments.callee;
- if (c._len <= arguments.length)
- return c._func.apply(null, arguments);
- return MochiKit.Base.bind(c, arguments);
- }
- g._len = n || f.length;
- g._func = f;
- return g;
- }
If keeping with the MochiKit spirit, one would save this function in the MochiKit.Base library and globally if export is active:
- (function(){
- // closure to avoid cluttering window
- function partialize(f, n) {
- var g = function() {
- var c = arguments.callee;
- if (c._len <= arguments.length)
- return c._func.apply(null, arguments);
- return MochiKit.Base.bind(c, arguments);
- }
- g._len = n || f.length;
- g._func = f;
- return g;
- }
- // save in MochiKit.Base:
- MochiKit.Base.partialize = partialize;
- // if export is active, save on window:
- if (MochiKit.__export__) window.partialize = partialize;
- })();
In prototype
If you are using Prototype, you probably do not dislike the use of extending built-in classes using the prototype chain, thus the implementation is a slight change of the implementation by Coglan:
- Function.prototype.toSelfCurrying = function(n) {
- var g = function() {
- var c = arguments.callee;
- if (arguments.length >= c._len)
- return c._func.apply(this, arguments);
- return c.curry.apply(c, arguments);
- };
- g._len = n || this.length;
- g._func = this;
- return g;
- };
UPDATE: Fixing typo pointed out by James Coglan.
This is almost as compact and just as readable.
Vote Reddit Story ?
























James Coglan said
at February 7 2008 @ 01:06
Quick typo fix: in your Prototype example, you need to call c.curry.apply() rather than method.curry.apply(), since ‘method’ is not defined in your version of my code.
Interesting to see different approaches. I won’t get into a debate about global functions, but I should point out that use of closures do not cause memory leaks. Memory leaks tend to be caused by circular references between JavaScript objects and DOM objects — closures can make such references hard to spot, but they do not cause the leaks. This has nothing to do with the DOM, in fact I’ve just been running my method millions of times through Drip and it shows constant memory usage.
James Coglan said
at February 7 2008 @ 01:08
Sorry, just realised my comment was ambiguous. By “This has nothing to do with the DOM”, I meant that partial function application (not memory leaks) has nothing to do with the DOM.
Barklund said
at February 7 2008 @ 10:42
Hi James,
I’ve fixed the typo, and regarding your comment on “to leak or not”, I have come to the habit of never using the activation object for variables that need be accessed inside inner functions. In this case, neither
fnorncan be DOM objects agreed (as they are supposed to be a function and an integer respectively), but if I for the fun of it (and for the errors it will throw) invoke it withnset to some DOM object, that I remove from the DOM afterwards, we might get a leak quite easily (not tested though).Thus I have come to the habit of never using the activation object in such smaller helper functions, that are generalized to work on just about anything.