Common Lisp: What does #+nil?
Asked Answered
C

2

7

The other day (perhaps yesterday) I was quite perplexed about this #+nil read-time conditional found in https://github.com/billstclair/defperson/blob/master/defperson.lisp#L289.

After some deep thinking I came to the conclusion that this is very lispy way of commenting out code. Can someone confirm this?

Perhaps my assumptions are completely wrong. Anyway, thanks in advance.

Currency answered 24/4, 2015 at 14:21 Comment(0)
P
5

See CLHS 2.4.8.17 Sharpsign Plus

To conditionalize reading expressions from input, Common Lisp uses feature expressions.

In this case it has been used to comment out a form.

It's a part of the reader. #+ looks if the next item, usually as a keyword symbol with the same name, is a member of the list *features*. If yes, the then next item is read as normal, if not, it is skipped.. Usually :NIL is not a member of that list, so the item is skipped. Thus it hides the expression from Lisp. There might have been a Lisp implementation, where this would not work : NIL, New Implementation of Lisp. It might have had the symbol :NIL on the *features* list, to indicate the name of the implementation.

Features like NIL are by default read in the keyword package:

  • #+NIL -> looks for :NIL in cl:*features*
  • #+CL:NIL -> looks for CL:NIL in cl:*features*

Example

(let ((string1 "#+nil foo bar"))             ; string to read from

  (print (read-from-string string1))         ; read from the string

  (let ((*features* (cons :nil *features*))) ; add :NIL to *features*
    (print (read-from-string string1)))      ; read from the string

  (values))                                  ; return no values

It prints:

BAR 
FOO 

Note that Common Lisp has other ways to comment out forms:

; (sin 3) should we use that?

#| (sin 3)  should we use that?
   (cos 3)  or this?            |#
Palmapalmaceous answered 24/4, 2015 at 14:56 Comment(3)
As a note; it looks like SBCL ignores #+nil ... expressions even when NIL is in *features*. If written in a file, then loaded, the following prints "Nope": (push nil *features*) #+nil (format t "NIL is in *features*") #-nil (format t "Nope").Nepenthe
@Nepenthe that is because the feature expression is read into the keyword package. :NIL would be the relevant symbol in *features*.Chabot
@m-n: Yup. Replacing the first expression above with (push :nil *features*) ... prints NIL is in *features*.Nepenthe
B
6

Yes, it is a lispy way of commenting code, but you shouldn't leave this out in production code.

A better alternative is #+(or).

It only takes one more character, it takes the same key presses if you use Emacs paredit or some other mode that automatically inserts the closing parenthesis, and it's not subject to the existence of the symbol :nil in *features*.

Berkley answered 24/4, 2015 at 16:5 Comment(3)
Thanks for the link. If I had found this earlier I wouldn't had to post my question, but #+nil is really hard to search for.Currency
Even better, though (at least in my opinion), is #-(and), because the #- seems more like commenting something out than #+ does.Thorstein
I sometimes use #+#:ignore if I'm feeling paranoid.Heterotopia
P
5

See CLHS 2.4.8.17 Sharpsign Plus

To conditionalize reading expressions from input, Common Lisp uses feature expressions.

In this case it has been used to comment out a form.

It's a part of the reader. #+ looks if the next item, usually as a keyword symbol with the same name, is a member of the list *features*. If yes, the then next item is read as normal, if not, it is skipped.. Usually :NIL is not a member of that list, so the item is skipped. Thus it hides the expression from Lisp. There might have been a Lisp implementation, where this would not work : NIL, New Implementation of Lisp. It might have had the symbol :NIL on the *features* list, to indicate the name of the implementation.

Features like NIL are by default read in the keyword package:

  • #+NIL -> looks for :NIL in cl:*features*
  • #+CL:NIL -> looks for CL:NIL in cl:*features*

Example

(let ((string1 "#+nil foo bar"))             ; string to read from

  (print (read-from-string string1))         ; read from the string

  (let ((*features* (cons :nil *features*))) ; add :NIL to *features*
    (print (read-from-string string1)))      ; read from the string

  (values))                                  ; return no values

It prints:

BAR 
FOO 

Note that Common Lisp has other ways to comment out forms:

; (sin 3) should we use that?

#| (sin 3)  should we use that?
   (cos 3)  or this?            |#
Palmapalmaceous answered 24/4, 2015 at 14:56 Comment(3)
As a note; it looks like SBCL ignores #+nil ... expressions even when NIL is in *features*. If written in a file, then loaded, the following prints "Nope": (push nil *features*) #+nil (format t "NIL is in *features*") #-nil (format t "Nope").Nepenthe
@Nepenthe that is because the feature expression is read into the keyword package. :NIL would be the relevant symbol in *features*.Chabot
@m-n: Yup. Replacing the first expression above with (push :nil *features*) ... prints NIL is in *features*.Nepenthe

© 2022 - 2024 — McMap. All rights reserved.