Что означает "#+" в коде cl-mysql?
Недавно я попытался прочитать код о cl-mysql, но застрял с #+
,
Пытался гуглить, но не работает, поэтому перейдите сюда
(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))
И похоже, что это для другого бэкэнда LISP компилятора. Но до сих пор не знаю, зачем писать что-то подобное. Любой может помочь мне объяснить, спасибо.
2 ответа
#+
макрос чтения, который проверяет наличие ключевого слова в специальной переменной *FEATURES*
, Если его там нет, следующая форма будет пропущена (читателем; компилятор никогда ее не увидит). Существует также #-
который делает обратное.
Есть некоторые вещи, которые не являются частью стандарта Common Lisp, но настолько важны, что все (или большинство) реализаций предоставляют для них нестандартное расширение. Когда вы хотите использовать их в коде, который должен работать в нескольких реализациях, вы должны использовать условия времени чтения, чтобы обеспечить правильный код для текущей реализации. Мьютексы (и потоки в целом) являются одной из таких вещей.
Конечно, могут быть функции, предоставляемые сторонними библиотеками. Содержание *FEATURES*
будет выглядеть примерно так:
(: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)
Поэтому, если вы хотите написать код, который зависит, например, от Quicklisp, вы можете использовать #+quicklisp
, Если вам нужен код, который запускается только в том случае, если Quicklisp недоступен, вы должны использовать #-quicklisp
,
Вы также можете использовать логическое выражение функций. Например,
#+(or sbcl ecl) (format t "Foo!")
будет печатать Foo!
на SBCL или ECL.
#+(and sbcl quicklisp) (format t "Bar!")
будет только печатать Bar!
на SBCL, который имеет Quicklisp доступны.
Можно представить, что мы можем написать:
(defun make-lock (name)
(cond ((member :sb-thread *features)
(sb-thread:make-mutex :name name))
((member :ecl *features*)
(mp:make-lock :name name))
...))
Но это обычно не работает, потому что мы не можем прочитать символы, когда их пакет не существует, а некоторые пакеты зависят от реализации / библиотеки / приложения. Пакеты не создаются во время чтения ленивым / автоматическим способом.
В Common Lisp чтение символа пакета, который не существует, приводит к ошибке:
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.
В вашем примере sb-thread:make-mutex
является символом, который имеет смысл в SBCL, но не в Allegro CL. Дополнительно пакет SB-THREAD
не существует в Allegro CL. Таким образом, Allegro CL должен быть защищен от чтения. В этом случае символ sb-thread:make-mutex
будет прочитан, только если функция sb-thread
присутствует на cl:*features*
список. Что, вероятно, только для SBCL или Lisp, который утверждает, что sb-threads
имеется в наличии.
Выражения функций здесь не позволяют Lisp пытаться прочитать символы с неизвестными пакетами - пакеты неизвестны, потому что соответствующее программное обеспечение не загружено или недоступно.