DIfferences between keywords and other symbols
Rainer Joswig's answer describes the symbols themselves pretty well. To summarize, though, each symbol belongs to a package. p::foo
(or p:foo
, if it's external) is a symbol in the package p
. If you try to evaluate it as form, you'll get its symbol-value, which you can set with set
, or `(setf symbol-value):
CL-USER> (set 'foo 'bar)
BAR
CL-USER> foo
BAR
CL-USER> (setf (symbol-value 'foo) 'baz)
BAZ
CL-USER> foo
BAZ
There's a special package named keyword
. You can write keyword::foo
if you want, but all of the keyword package's symbol are external, so you can write keyword:foo
instead. Because they're so commonly used, though, you even get a special syntax for them: :foo
. They've also got the special property that you can't set their value; their values are themselves:
CL-USER> :foo
:FOO
CL-USER> (symbol-value :bar)
:BAR
And that's really all there is that makes keyword symbols special, in and of themselves.
Keywords and other symbols as keyword names in lambda lists
What's probably a bit more important is that they are, by default, used as indicators for "keyword arguments" in lambda lists. E.g.,
CL-USER> ((lambda (&key foo bar)
(list foo bar))
:bar 23 :foo 12)
(12 23)
I can see that keyword symbols are mainly used for named parameters,
but I was asking myself if it was not possible to implement this using
quoted symbols as well?
The syntax for lambda lists actually lets you do a lot more customization with the keyword arguments. A common thing is to specify default values:
CL-USER> ((lambda (&key (foo 'default-foo) bar)
(list foo bar))
:bar 23)
(DEFAULT-FOO 23)
You can also provide a variable name that gets bound to a boolean indicating whether the parameter was specified or not:
CL-USER> ((lambda (&key (foo 'default-foo foo-p) (bar 'default-bar bar-p))
(format t "~{~A:~7t~A~%~}"
(list 'foo foo
'foo-p foo-p
'bar bar
'bar-p bar-p)))
:bar 23)
FOO: DEFAULT-FOO
FOO-P: NIL
BAR: 23
BAR-P: T
The full syntax for from 3.4.1 Ordinary Lambda Lists lets us do even more, though. It's
lambda-list::= (var*
[&optional {var | (var [init-form [supplied-p-parameter]])}*]
[&rest var]
[&key {var | ({var | (keyword-name var)} [init-form [supplied-p-parameter]])}* [&allow-other-keys]]
[&aux {var | (var [init-form])}*])
Note that you can specify the keyword-name
. It defaults to the symbol in the keyword package with the same name as var
, but you can actually provide it and specify your own "keywords". This can be handy, e.g., if you want a descriptive keyword name but don't want such a long variable name:
CL-USER> ((lambda (&key ((:home-directory dir)))
(list dir))
:home-directory "/home/me")
("/home/me")
You can also use it to specify keyword names that aren't keyword symbols:
CL-USER> ((lambda (&key ((surprise surprise)))
(list surprise))
'surprise "hello world!")
("hello world!")
You can combine the two, too:
CL-USER> ((lambda (&key ((hidden-parameter secret)))
(format t "the secret is ~A" secret))
'hidden-parameter 42)
the secret is 42
You can mix that with default values as well, but you probably get the point by now.
(frob bar baz :from-end t 'frobber::include-debug-output t)
. – Blight