What are "downward funargs"?

Functional ProgrammingLispTerminology

Functional Programming Problem Overview


Jamie Zawinski uses that term in his (1997) article "java sucks" as if you should know what it means:

> I really hate the lack of downward-funargs; anonymous classes are a lame substitute. (I can live without long-lived closures, but I find lack of function pointers a huge pain.)

It seems to be Lisper's slang, and I could find the following brief definition here, but somehow, I think I still don't get it:

> Many closures are used only during the extent of the bindings they refer to; these are known as "downward funargs" in Lisp parlance.

Were it not for Steve Yegge, I'd just feel stupid now, but it seems, it might be OK to ask:

> Jamie Zawinski is a hero. A living legend. [...] A guy who can use the term "downward funargs" and then glare at you just daring you to ask him to explain it, you cretin. > > -- XEmacs is dead, long live XEmacs

So is there a Lisper here who can compile this for C-style-programmers like me?

Functional Programming Solutions


Solution 1 - Functional Programming

Downward funargs are local functions that are not returned or otherwise leave their declaration scope. They only can be passed downwards to other functions from the current scope.

Two examples. This is a downward funarg:

function () {
    var a = 42;
    var f = function () { return a + 1; }
    foo(f); // `foo` is a function declared somewhere else.
}

While this is not:

function () {
    var a = 42;
    var f = function () { return a + 1; }
    return f;
}

Solution 2 - Functional Programming

To better understand where the term comes from, you need to know some history.

The reason why an old Lisp hacker might distinguish downward funargs from funargs in general is that downward funargs are easy to implement in a traditional Lisp that lacks lexical variables, whereas the general case is hard.

Traditionally a local variable was implemented in a Lisp interpreter by adding a binding (the symbol name of the variable, paired with its value) to the environment. Such an environment was simple to implement using an association list. Each function had its own environment, and a pointer to the environment of the parent function. A variable reference was resolved by looking in the current environment, and if not found there, then in the parent environment, and so on up the stack of environments until the global environment was reached.

In such an implementation, local variables shadow global variables with the same name. For example, in Emacs Lisp, print-length is a global variable that specifies the maximum length of list to print before abbreviating it. By binding this variable around the call to a function you can change the behaviour of print statements within that function:

(defun foo () (print '(1 2 3 4 5 6))) ; output depends on the value of print-length

(foo) ; use global value of print-length ==> (1 2 3 4 5 6)

(let ((print-length 3)) (foo)) ; bind print-length locally around the call to foo. ==> (1 2 3 ...)

You can see that in such an implementation, downward funargs are really easy to implement, because variables that are in the environment of the function when it's created will still be in the environment of the function when it's evaluated.

Variables that act like this are called special or dynamic variables, and you can create them in Common Lisp using the http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/dec_special.html#special"><code>special</code></a> declaration.

Solution 3 - Functional Programming

In Common Lisp:

(let ((a 3))
  (mapcar (lambda (b) (+ a b))
          (list 1 2 3 4)))

->  (4 5 6 7)

In above form the lambda function is passed DOWNWARD. When called by the higher-order function MAPCAR (which gets a function and a list of values as arguments, and then applies the function to each element of the list and returns a list of the results), the lambda function still refers to the variable 'a' from the LET expression. But it happens all within the LET expression.

Compare above with this version:

(mapcar (let ((a 3))
          (lambda (b) (+ a b)))
        (list 1 2 3 4))

Here the lambda function is returned from the LET. UPWARD a bit. It then gets passed to the MAPCAR. When MAPCAR calls the lambda function, its surrounding LET is no longer executing - still the function needs to reference the variable 'a' from the LET.

Solution 4 - Functional Programming

There's a pretty descriptive article on Wiki called Funarg problem

> "A downwards funarg may also refer to > a function's state when that function > is not actually executing. However, > because, by definition, the existence > of a downwards funarg is contained in > the execution of the function that > creates it, the activation record for > the function can usually still be > stored on the stack."

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHanno FietzView Question on Stackoverflow
Solution 1 - Functional ProgrammingKonrad RudolphView Answer on Stackoverflow
Solution 2 - Functional ProgrammingGareth ReesView Answer on Stackoverflow
Solution 3 - Functional ProgrammingRainer JoswigView Answer on Stackoverflow
Solution 4 - Functional ProgrammingÓlafur WaageView Answer on Stackoverflow