What's the meaning of "#+" in the code of cl-mysql? [duplicate]
Asked Answered
P

2

7

Recently I tried to read code about cl-mysql, but got stuck with the #+.

Tried to google it, but not work, so turn to here

(defun make-lock (name)
  #+sb-thread (sb-thread:make-mutex :name name)
  #+ecl (mp:make-lock :name name)
  #+armedbear (ext:make-thread-lock)
  #+ (and clisp mt) (mt:make-mutex :name name)
  #+allegro (mp:make-process-lock :name name))

And looks like it is for different backend lisp compiler. But still no idea why write something like this. Anyone can help me make it clear, thx.

Piscatelli answered 3/5, 2016 at 7:25 Comment(2)
Also see: Common Lisp: What does #+nil?, What does #+#. mean in lisp?, operator #+ and #- in .sbclrcMiserly
I closed this as a duplicate, since it's been answered in other questions, but I upvoted it because this it's a good example of how this construction is used and, as you noted, it is rather tough to search for this until you know what it's called (at which point you usually don't need to search for it any more).Miserly
Q
11

#+ is a reader-macro that checks if a keyword is in the special variable *FEATURES*. If it isn't there, the following form will be skipped over (by the reader; the compiler will never see it). There is also #- which does the opposite.

There are some things that aren't part of the Common Lisp standard, but are important enough that all (or most) implementations provide a non-standard extension for them. When you want to use them in code that needs to work on multiple implementations, you have to use read-time conditionals to provide the correct code for the current implementation. Mutexes (and threads in general) are one of those things.

Of course there may be features provided by third party libraries as well. The contents of *FEATURES* will look something like this:

(:SWANK :QUICKLISP :SB-BSD-SOCKETS-ADDRINFO :ASDF-PACKAGE-SYSTEM :ASDF3.1
 :ASDF3 :ASDF2 :ASDF :OS-UNIX :NON-BASE-CHARS-EXIST-P :ASDF-UNICODE :64-BIT
 :64-BIT-REGISTERS :ALIEN-CALLBACKS :ANSI-CL :ASH-RIGHT-VOPS
 :C-STACK-IS-CONTROL-STACK :COMMON-LISP :COMPARE-AND-SWAP-VOPS
 :COMPLEX-FLOAT-VOPS :CYCLE-COUNTER :ELF :FLOAT-EQL-VOPS
 :FP-AND-PC-STANDARD-SAVE :GENCGC :IEEE-FLOATING-POINT :INLINE-CONSTANTS
 :INTEGER-EQL-VOP :INTERLEAVED-RAW-SLOTS :LARGEFILE :LINKAGE-TABLE :LINUX
 :LITTLE-ENDIAN :MEMORY-BARRIER-VOPS :MULTIPLY-HIGH-VOPS :OS-PROVIDES-DLADDR
 :OS-PROVIDES-DLOPEN :OS-PROVIDES-GETPROTOBY-R :OS-PROVIDES-POLL
 :OS-PROVIDES-PUTWC :OS-PROVIDES-SUSECONDS-T :PACKAGE-LOCAL-NICKNAMES
 :PRECISE-ARG-COUNT-ERROR :RAW-INSTANCE-INIT-VOPS :SB-DOC :SB-EVAL :SB-FUTEX
 :SB-LDB :SB-PACKAGE-LOCKS :SB-SIMD-PACK :SB-SOURCE-LOCATIONS :SB-TEST
 :SB-THREAD :SB-UNICODE :SBCL :STACK-ALLOCATABLE-CLOSURES
 :STACK-ALLOCATABLE-FIXED-OBJECTS :STACK-ALLOCATABLE-LISTS
 :STACK-ALLOCATABLE-VECTORS :STACK-GROWS-DOWNWARD-NOT-UPWARD :SYMBOL-INFO-VOPS
 :UNIX :UNWIND-TO-FRAME-AND-CALL-VOP :X86-64)

So if you wanted to write code that depends on Quicklisp for example, you could use #+quicklisp. If you wanted code that is only run if Quicklisp is not available, you'd use #-quicklisp.

You can also use a boolean expression of features. For example,

#+(or sbcl ecl) (format t "Foo!")

would print Foo! on either SBCL or ECL.

#+(and sbcl quicklisp) (format t "Bar!")

would only print Bar! on SBCL that has Quicklisp available.

Quadrennial answered 3/5, 2016 at 7:59 Comment(1)
Thanks for your comments, really thanksPiscatelli
H
5

One could imagine that we can write:

(defun make-lock (name)
  (cond ((member :sb-thread *features)
         (sb-thread:make-mutex :name name))
        ((member :ecl *features*)
         (mp:make-lock :name name))
     ...))

But that does usually not work, because we can't read symbols when their package is not existing and some packages are implementation/library/application specific. Packages are not created at read time in a lazy/automatic fashion.

In Common Lisp, reading a symbol of a package, which does not exist, leads to an error:

CL-USER 1 > (read-from-string "foo:bar")

Error: Reader cannot find package FOO.
  1 (continue) Create the FOO package.
  2 Use another package instead of FOO.
  3 Try finding package FOO again.
  4 (abort) Return to level 0.
  5 Return to top loop level 0.

In your example sb-thread:make-mutex is a symbol which makes sense in SBCL, but not in Allegro CL. Additionally the package SB-THREAD does not exist in Allegro CL. Thus Allegro CL needs to be protected from reading it. In this case, the symbol sb-thread:make-mutex will only be read, if the the feature sb-thread is present on the cl:*features* list. Which is likely only for SBCL, or a Lisp which claims to have sb-threads available.

The feature expressions here prevents the Lisp from trying to read symbols with unknown packages - the packages are unknown, because the respective software is not loaded or not available.

Harrovian answered 3/5, 2016 at 10:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.