10
$\begingroup$

In many modern languages, a function is just a specific kind of value that happens to be callable. However, some languages, even if they support first-class functions, assign functions to their own namespace separate from values.

In Common Lisp, functions and values occupy different namespaces. A function can be realized as a value with the (function ...) special form (abbreviated #'). To call a function that has been reified in this way, you use the funcall form.

What are the advantages to placing functions in their own namespace, separate from values?

$\endgroup$
4
  • $\begingroup$ Related SE question: stackoverflow.com/q/1020968/8234919 $\endgroup$ May 17, 2023 at 19:17
  • $\begingroup$ If functions and variables were in a different namespace, that would rule out function pointers. $\endgroup$ May 23, 2023 at 23:43
  • $\begingroup$ @user16217248 Not necessarily. Common Lisp provides a primitive that takes a function name and constructs a callable value representing that function. It's just that in a Lisp-2 (a language with two namespaces), the process isn't automatic; you have to ask for the function pointer rather than just using the function name and having the interpreter figure it out. $\endgroup$ May 24, 2023 at 2:30
  • 1
    $\begingroup$ Other Lisp-2 type languages: Ruby, Perl, Elixir, R, Emacs Lisp, ISLisp. $\endgroup$ Nov 14, 2023 at 10:11

1 Answer 1

6
$\begingroup$

This is commonly known as the "Lisp-1 versus Lisp-2" question, after a 1988 paper by Richard P. Gabriel and Kent Pitman. Scheme is a Lisp-1 and Common Lisp is a Lisp-2; the term isn't related to the language LISP 2, which never went anywhere. Both terms are also extended to non-Lisp languages with similar namespace choices. Python is a Lisp-1, while Java is a Lisp-2. Some languages are harder to classify, or have more than that.

It is a trite thing to say, but one key advantage for the programmer in a Lisp-2 is just that you can have a function and variable with the same name. That could be simply using a convenient name for a variable without interference from a function: sum = sum(values), which wouldn't be out of place in Java-like code. It's also not uncommon for Common Lisp code to make use of this duality on purpose, storing associated data of a function within the value cell of its name. This is a real benefit to the programmer, even though it's not strictly necessary for anything.

From the language's perspective, a separate function namespace means you can offer function-specific operations directly, such as function algebras or instrumentation, without overwhelming the general namespace. It can also, for example, enforce access restrictions on functions segregated from values. These sorts of features are possible in a Lisp-1, but may be slightly more accessible in a Lisp-2.

On the implementation side, always knowing that the thing you're trying to call is a function, and perhaps what specific function it is, can be helpful. "A value that's callable" can impose meaningful additional bookkeeping or indirection, with associated performance costs. It can also raise complications for language features like virtual methods, or perhaps non-virtual methods, depending on the surrounding semantics. A Lisp-2 always makes clear what you're dealing with.


The major disadvantage of a Lisp-2 is exactly what you mention in the question: converting a function to a value, or using such a value as a function, is annoying, and higher-order functions are more difficult to write or use. Some might also say that it should be, and that friction has the purpose of discouraging that style of code; that is a question of the philosophy of the language. More recently, a number of languages that are fundamentally Lisp-2s have added features and syntax enabling more Lisp-1-style programming, such as C#'s automated method group conversions, striking more of a balance in between.

Another is, again, simply that there are two things with the same name, and there's a semantic burden in knowing which of the two is in use here. I don't like to underestimate that cost, though in practice people seem to deal with it without issue.


There are some peculiarities specific to Lisp itself that I won't treat in detail here, including the possibility of putting non-function values into the function namespace, and the once-current, now-obsolete concerns about the memory footprint of a dual namespace.


In any case, things can be a bit hazier in reality than this neat distinction sets out. Most of the time, for most users, this distinction doesn't matter, though it's a critical one from the language designer's perspective.

It's not uncommon for what's otherwise a Lisp-1 to have a separate namespace of types, with all the same attendant issues as functions in a Lisp-2 — but less common to have complaints about those. We can also look at a language like Perl, which has, I think, five separate namespaces in common and visible use (scalar, array, hash, sub (function), file), though with some intentionally very blurred lines. It tends not to have the same sorts of friction, all the same, and some of its affordances might be useful to other languages.

There is also Bertrand Meyer's Uniform Access Principle, which in most respects implies something in between a Lisp-1 and Lisp-2: you can't distinguish something implemented as a variable from a function, so they must be the same namespace, but implicitly getting a function reference is also difficult. It's primarily an OO thing, but highlights a nether space where things aren't as clear as all that.

There are whole classes of language where this question has different, or moot, implications, even when there are first-class functions; concatenative languages might be one example, and languages that focus on RPC or message-send semantics might be another. My personal preference is a system where this doesn't matter to the user: providing easy affordances for getting between namespaces, or supporting namespaced operations, is more important in practice than the underlying model to the programmer almost all the time.

$\endgroup$
1
  • $\begingroup$ "the possibility of putting non-function values into the function namespace" is this something that exists? $\endgroup$
    – coredump
    Jul 22, 2023 at 10:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .