Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Looking for a tutorial that clearly explains usage of the #+/- tag in lisp code

79 views
Skip to first unread message

arthur...@gmail.com

unread,
Jul 21, 2012, 5:52:01 PM7/21/12
to
Until now, I have been able to avoid dealing with implementation dependent lisp, but now I have been given the task of resurrecting some very old code that contains a lot inline # for dealing with implementation dependent features and I need to know whether I am understanding them correctly. I have always assumed that if I see #+foo preceding a lisp form, then that means execute the form if foo exists and if I see #-foo preceding a form then execute the form if foo does not exist. Are these symbols stored in *features* ? Is there a way to evaluate them in the REPL, so I can see what they are returning.

for example

#+symbolics
(push :clos *features*)

#-:clos
(unless (find-package 'pcl)(require 'pcl))

Pascal J. Bourguignon

unread,
Jul 21, 2012, 6:27:57 PM7/21/12
to
arthur...@gmail.com writes:

> Until now, I have been able to avoid dealing with implementation
> dependent lisp, but now I have been given the task of resurrecting
> some very old code that contains a lot inline # for dealing with
> implementation dependent features and I need to know whether I am
> understanding them correctly. I have always assumed that if I see
> #+foo preceding a lisp form, then that means execute the form if foo
> exists and if I see #-foo preceding a form then execute the form if
> foo does not exist. Are these symbols stored in *features* ?

Yes and no. #+ and #- read the following symbols with *package* bound
to the KEYWORD package. It doesn't override any other readtable or
reader variable, so #+foo tests for (member :FOO *features*) with the
default readtable settings.

Similarly in #+(and) the expression read and evaluated is actually (:AND).
#+ and #- have special rules to evaluatre (:AND …), (:OR …) and (:NOT …).


You can also test of a specific symbol in a specific package by
qualifying it:

(pushnew 'my-package:present *features*)

#+my-package:present (my-package:do-something)



> Is there a way to evaluate them in the REPL, so I can see what they
> are returning.


The easiest way is to use #+:

#+foo t #-foo nil

or:

'(#+foo t)

otherwise you can use this eval-feature function:

(defun eval-feature (expression)
"Evaluates a feature expression as a BOOLEAN."
(flet ((illegal-feature ()
(error "illegal feature ~S" expression)))
(cond
;; Some implementations accept any atom:
((atom expression)
(not (null (member expression *features*))))
(t (case (first expression)
((:not) (if (cddr expression)
(illegal-feature)
(not (eval-feature (second expression)))))
((:and) (every (function eval-feature) (rest expression)))
((:or) (some (function eval-feature) (rest expression)))
(t (illegal-feature)))))))

(eval-feature '(:and :ccl :darwin))
--> nil
(eval-feature '(:and :ccl :linux))
--> t
#+(and ccl linux) t #-(and ccl linux) nil
--> t


Notice that EVAL-FEATURE expects the expression as it would have been
read by #+/#-, ie. with keywords.


> for example
>
> #+symbolics
> (push :clos *features*)
>
> #-:clos
> (unless (find-package 'pcl)(require 'pcl))

#+foo and #+:foo are identical.


While it's not complete and not necessarily up-to-date, you may have a
look at http://cliki.net/features


Of course, if your sources are litered with a lot of #+/#- it'll be a
maintainance nightmare. Just like C #ifdef/#ifndef, it should be
restricted to a small OS/implementation interface layer and the rest of
the software should use that layer with no need for #+/#-. Then you can
also choose to implement this layer in different files for different OS
or implementations, and just load one or another of these files
depending on the OS or implementation, ie. needing #+/#- only in the
ASDF file (or in the Makefile for C projects). But strangely,
programming against clean interfaces doesn't seem to be to the taste of
a lot of people :-(

--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

arthur...@gmail.com

unread,
Jul 21, 2012, 6:47:32 PM7/21/12
to
Pascal,

Thanks very much for the detailed response. The code I am looking at is littered with #+ and #- for dealing with different hardware platforms, operating systems, and CLOS versus PCL. Luckily most of them are obsolete.

Arthur
> (unless (find-package 'pcl)(require 'pcl))

0 new messages