incognito-keywords
incognito-keywords introduces a new kind of keyword that looks just like any non-keyword symbol
and allows safe usage of convenient but clashy symbol names by multiple libraries without conflicts through sharing.
Some names that might benefit are
alist
, blist
, plist
, macro
, operator
, index
, &doc
, &decl
, &rest+
, &destructure
, &ignored
and &ignorable
.
⚓
incognito keywords, or "ikeywords" for short, are useful targets for various kinds of dispatching.
(define (macro
my-macro) ...)
;; blends much better with:
(define (variable my-variable) ...) ; VARIABLE is exported from CL.
;; than would:
(define (:macro my-macro))
;; And the following:
(define (macro my-macro) ...) ; MACRO being a normal symbol
;; would very likely result in symbol conflicts.
(map 'alist
...)
(do-for ((i (index
:from 1))
(((&ignored
key) value) (plist
my-plist)))
...)
(ikeywords:defpackage #:do-for.ikeywords
(:export #:index
#:&ignored
#:plist
...))
(defpackage #:do-for-user-package
(:use #:cl #:do-for-ikeywords)
(:import-from #:do-for #:do-for))
(locate 'macro
"my-macro")
In the examples above, define
, map
, do-for
and locate
could come from different libraries by different authors. If they all use ikeywords as appropriate, then their users can use all these libraries from one package without symbol conflicts!
⚓
Usage of incognito-keywords is very easy!
First of all, in the way of packages there's the incognito-keywords
package, which is also nicknamed ikeywords
. It exports the functions package
and ensure
and the macro defpackage
. These symbols should be explicitly qualified. For example, ikeywords:defpackage
instead of (:use #:ikeywords)
or (:import-from #:ikeywords #:defpackage)
.
ikeywords live in the ikeyword
package and are typically created implicitly with ikeywords:defpackage
, but it's also possible to create some dynamically with ikeywords:ensure
.
Macro
defpackage
name &rest options => new-or-redefined-package-
A very simplified version of cl:defpackage dedicated to creation of "ikeyword packages". The syntax is just like cl:defpackage, except that only the :export, :nicknames, :documentation and :size options are supported. The package will implicitly use the IKEYWORD package. All the symbol names in :export clauses will be passed to ENSURE. The :nicknames, :documentation and :size options are passed straight through to cl:defpackage.
It's possible to obtain a list of all ikeyword packages with:
(package-used-by-list (
ikeywords:package
)) Function
ensure
name => new-or-existing-ikeyword-
If name already names an ikeyword (a symbol in the
ikeyword
package), then return that ikeyword.Else, create the ikeyword (interning a symbol with that name in the
ikeyword
package), immediately export it (from theikeyword
package), then return the new ikeyword.Attempting to create an ikeyword with the name of one of the 978 symbols in the
common-lisp
package is an error, as this would almost inevitably result in symbol conflicts, which would defeat the whole point of ikeywords! Function
package
=> ikeyword-package-
This convenience function simply returns the
ikeyword
package.It's basically equivalent to
(find-package '#:ikeyword)
.
⚓
incognito-keywords' reason to exist is to allow libraries to make use of some very desirable symbol names, while avoiding the excessive symbol conflicts this would normally incur. However, incorrect usage of this library could actually increase (definition) conflicts. So please carefully consider the following:
Libraries should not create global definitions for Common Lisp functions, macros, setf
expanders, etc. on ikeywords, as any two libraries that do this can't be safely loaded in the same image.
However, if a library creates a new kind of definition in another "namespace", then this library can safely create such definitions on these symbols. However, if that library exports a way to create such definitions, then users of that library can't safely create such definitions on ikeywords.
For this reason, libraries in this situation should provide any appropriate definitions on ikeywords using their new exported definition mechanisms, and prohibit their users, through mechanism and/or policy, from providing any new definitions on those ikeywords.