Anonymous Recursive Functions

I learned this “trick” some time ago, while reading the source code for the MooTools JavaScript framework (version 1.1, I think).

I used this “trick” not so long ago, when developing the Spacetree visualization for the JavaScript InfoVis Toolkit library.

When clicking a node, the Spacetree visualization unselects all tree nodes and then selects the nodes in between the root node and the selected node. This can be implemented as a recursive function, since we have to iterate through the clicked node and its ancestors to set those nodes as selected.

I defined an anonymous recursive function that receives a node and a special value as formal parameters, and sets the selected property from this node and its ancestors to the specified value:

  (function(node, val) {
      if(node == null) return;
      node.selected = val;
      return arguments.callee(node.parent, val);
  })

arguments.callee holds a reference to the defined function.
You can check that by copying this code:

  (function(text) {
    alert(arguments.callee);
    alert(text);
  })("some text");

and running it in your Firefox console.

Unfortunately, our anonymous recursive function needs to be called more than once, since we first need to unselect previous selected nodes, and then to select the nodes in between the clicked node and the root node.
Similar to the “return this” trick to chain method calls, we can add “return arguments.callee” to chain function calls.

  (function(node, val) {
      if(node == null) return arguments.callee;
      node.selected = val;
      return arguments.callee(node.parent, val);
  })

This way, we can call our function multiple times. I’ll first pass the previous clicked node in order to unselect the previous selected path, and then I’ll pass the new clicked node in order to select our new path:

  (function(node, val) {
      if(node == null) return arguments.callee;
      node.selected = val;
      return arguments.callee(node.parent, val);
  })(nodePrev, false)(nodeNew, true);

What’s more interesting though, it’s trying to do the same thing in another language, like Lisp or OCaml.
Who knows, you might sumble upon the Y combinator.

7 Responses to “Anonymous Recursive Functions”


  1. 1 Mike McNally

    I know this may take the fun out of your post, but it’s possible to give your function a name. After the “function” keyword can come an identifier, and that’s bound in a way similar to what “letrec” does in Scheme.

  2. 2 salty-horse

    What are the benefits of using the function anonymously instead of naming it?

  3. 3 Nicolas

    Namespacing. By using anonymous functions you are not polluting the namespace with function names. The equivalent way of doing this with named functions would be to use a closure like this:

      (function() {
        var selectPath = function(node, val) {
          if(node == null) return;
          node.selected = val;
          return selectPath(node.parent, val);
        };
        selectPath(nodePrev, false);
        selectPath(nodeNew, true);
      })();
    

    That way you’d be avoiding stepping into some other defined variable with the same name.

  4. 4 Matt Might

    If you take the Y combinator approach, then you can also memoize recursive functions:

    http://matt.might.net/articles/implementation-of-recursive-fixed-point-y-combinator-in-javascript-for-memoization/

  5. 5 Nicolas

    Very interesting post Matt, thanks for pointing that :)

  6. 6 Kyle Simpson

    @Nicolas-
    I think Mike McNally’s post was meant to suggest that you can do this, which is the syntax often called “named functions” or “named anonymous functions”:

    (function trav(node, val) {
        if(node == null) return trav;
        node.selected = val;
        return trav(node.parent, val);
    })(nodePrev, false)(nodeNew, true);
    

    You’ll notice the use of the name “trav” right after the function keyword allows you to refer to it by name inside itself for the recursion (as well as the chainability “return”). I’ve read that arguments.callee is less performant than a named function reference, which would especially be an important factor in regards to recursion. I’ve never tested this myself, and honestly, I usually use “arguments.callee” in these cases, but I figured it was helpful to contrast it with a slight alternative.

    The only downfall here is that with only the above, “trav” becomes a defined function reference outside the function block scope in question. You could of course wrap the above in an outer “(function(){…})();” scoping block, and get both better performance as well as namespace protection, preventing “trav” from leaking out into the outer variable scope.

  7. 7 Nicolas

    @Kyle, Mike: I agree with you. Actually, my response to salty-horse talks about namespacing and how to define a named function without messing around with namespacing (just by creating an “outside” closure). I haven’t tested that code, but it should work.

    Your code is nicer though :)
    As you pointed out, just by putting an outside closure there one could protect it from namespacing:

    (function() {
      (function trav(node, val) {
          if(node == null) return trav;
          node.selected = val;
          return trav(node.parent, val);
      })(nodePrev, false)(nodeNew, true);
    })();
    

    However, I’m not sure about the performance of that code.

Comments are currently closed.