'() vs () in Common Lisp
Asked Answered
L

4

5

In Common Lisp, it seems like () is a self-evaluating form. That is, it evaluates to itself (or its alias nil). So there would seem to be no need to quote it. But using grep on my quicklisp directory finds numerous instances of '(), written by many different people in many different projects. Is there a technical reason for writing out the quoted version? Common Lisp the Lanugage, 2nd Edition, Section 1.2.2, mentions the stylistic differences where you may want to emphasize empty lists with (), and boolean false with nil, but does not cover this question. One of the examples Steele uses is:

(append '() '())

...which I believe could be written just as well as:

(append () ())

...so why throw the extra QUOTEs in there? Certainly it doesn't hurt things. Stylistically, is one form generally preferred to the other? Someone could certainly make the case that quoted form makes it simpler to add elements to in case you change your mind, and really want a non-empty literal list instead. Or that there is a certain symmetry in using the quote, because a non-empty literal list would also need it.

Is this historical baggage hanging around from other/older related languages that have been carried on by tradition?

This is unlike Scheme, where you do need to quote it. And it seems like you don't have to quote it in elisp, so maybe in a round-about way it could be related to lisp-1 vs. lisp-2?

Lubberly answered 24/5, 2016 at 22:15 Comment(1)
Actually, that section of CLtL2 got expanded to this section of the specification.Lanai
L
9

The quote has a very informative property, stating clearly that you mean that the token is supposed to be literal data. More so when you or a coworker revisits the code years later.

You must use () (without the quote) to declare an empty list in non-evaluated forms, such as a parameter list or class super-classes and slots, where the quote will actually cause harm. Actually, you can use nil as well, but you shouldn't, for clarity, when the declared thing is a list.


Here's a relevant excerpt from the specification:

1.4.1.4.4 NIL

nil has a variety of meanings. It is a symbol in the COMMON-LISP package with the name "NIL", it is boolean (and generalized boolean) false, it is the empty list, and it is the name of the empty type (a subtype of all types).

Within Common Lisp, nil can be notated interchangeably as either NIL or (). By convention, the choice of notation offers a hint as to which of its many roles it is playing.

For Evaluation?  Notation  Typically Implied Role       
----------
Yes              nil       use as a boolean.            
Yes              'nil      use as a symbol.             
Yes              '()       use as an empty list         
No               nil       use as a symbol or boolean.  
No               ()        use as an empty list.        

Figure 1-1. Notations for NIL

Within this document only, nil is also sometimes notated as false to emphasize its role as a boolean.

For example:

(print ())                          ;avoided
(defun three nil 3)                 ;avoided 
'(nil nil)                          ;list of two symbols
'(() ())                            ;list of empty lists
(defun three () 3)                  ;Emphasize empty parameter list.
(append '() '()) =>  ()              ;Emphasize use of empty lists
(not nil) =>  true                   ;Emphasize use as Boolean false
(get 'nil 'color)                   ;Emphasize use as a symbol

A function is sometimes said to “be false” or “be true” in some circumstance. Since no function object can be the same as nil and all function objects represent true when viewed as booleans, it would be meaningless to say that the function was literally false and uninteresting to say that it was literally true. Instead, these phrases are just traditional alternative ways of saying that the function “returns false” or “returns true,” respectively.

Lanai answered 25/5, 2016 at 10:54 Comment(1)
I'd like to add to this the “dumb programmer argument.” If I see a '(), I know that I could add elements to it because it's meant as a quoted list of 0 elements. If I see a (), I may have to consider a bit more of the context before deciding whether to change it to a list. ie: '() ⇒ '(a b c) makes more intuitive sense to me than () ⇒ '(a b c)Publication
Q
4

There's a reason to prefer writing '() to () even if () is self-evaluating. It makes the code easier to read because it's visually obvious that you're dealing with a datum, not an evaluated form.

It's similar to the reason to prefer writing '#(foo bar baz (+ 1 2)) to #(foo bar baz (+ 1 2)). Both evaluate to the same thing, but the former makes it visually obvious that the foo, bar, baz, and (+ 1 2) within are not evaluated.

Queeniequeenly answered 25/5, 2016 at 0:1 Comment(4)
Using quoted data structures (be it a list, or a vector) makes them part of the code and it's not a conforming behaviour to modify them whatsoever (however most implementations will let you do that) which results are unspecified (i.e implementation is free to throw a segfault).Output
@DanielKochmański That is not really a problem here: quoting does not change the fact that you already have a literal vector with #(a b c) syntax, which should not be modified.Miceli
I am not convinced by the readability argument. Adding a quote looks like you want a different behavior than with the unquoted version, even though they evaluate to the same value; I would find this confusing (and apparently OP is confused too). Quoting, backquoting, etc. can be hard to get right without a clear understanding of how it works, and IMO useless quotes add noise.Miceli
A valid argument. In The land of Lisp Conrad mentions in a section about the 4 representations of the one nil value that while not quoting () is allowed it breaks the convention that it's data and not code.Kocher
M
3

I never quote NIL , () or T, and certainly not numbers or strings.

If I read '() in someone's code, I am likely to be confused about the author's intent and maybe his/her understanding of quote in Common Lisp (beginner's question over here tend to show confusion with quotes).

I can't speak about the possibility that some implementations of CL would have needed, at some point, to quote (), but it is more likely that the author has experience with other flavors of Lisp and tries to apply this experience to Common Lisp, out of habit or on purpose.

The only case where I think it could make sense to quote () is when a previously non-empty constant list was emptied and someone did not bother to remove the quote.

(defvar *options* '(debug))

... becomes

(defvar *options* '())

It could even make sense to keep the quote in case you plan to change the defaults later.

Miceli answered 25/5, 2016 at 7:43 Comment(2)
Your answer is primarily opinion-based, I mean, you're only seeing it from your perspective. It actually makes a lot of sense to outright write '() without ever having written anything in-between the parentheses to clearly state it's data, and it's a lot less confusing than (), which should be used in non-evaluated list forms. In my opinion (heh, this is a comment after all), if I see () in an evaluated form, my thought is "was this intended or did the author forget to write the contents of an expression?" If I know the author's style, I barely squint though.Lanai
@Lanai As a style matter, I don't see a reason not to conform to other people's expectations and apparently many like to quote the empty list where not strictly required. Now, if you treated () as code, you could say that () is a degenerate case for reading compound forms where the return value is an empty list, just as (list), which is sometimes used too and even more explicit. But in the end it does not change the result, it is just good old NIL in disguise.Miceli
K
2

In Common Lisp () and nil are both representations of nil and it's self evaluating. Everything that is quoted evaluates to it's argument, but since the argument is nil which is self evaluating the result is the same. The compiled code will most likely be identical.

Scheme was originally interpreted under a predecessor to CL and in the first reports they more or less just made a lisp with lexical closure and one namespace and not much more. It looked more like CL than Scheme, but was a LISP1 so the empty list rules cannot be about Lisp1 vs Lisp2 since Scheme was a Lisp1 from the first report that didn't require quoting and has nil as a false value.

For every consecutive version of the report Scheme has been refining its syntax and naming conversions. The revisions did subtle changes and they were not afraid of making breaking changes. They introduced new booleans, changed their names, changed the booolean value of the empty list from false to true, removed nil and t as alias to #t and #f and deemed () an invalid expression thus requiring '().

Since it doesn't matter how you do it in CL perhaps some people who codes in both languages just want to have some symmetry in their lives. I certainly do this, but I cannot speak for all schemers.

Kocher answered 24/5, 2016 at 23:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.