Another feature of Lisp that newcomers might not have encountered in a brief introduction to the language is the manipulation of dispatch macro characters with get-dispatch-macro-character and set-dispatch-macro-character. We’ve just spent a bit of time talking about readtables, particularly the default readtable in Common Lisp, in quite general terms in the article on gensym. Now, let’s talk about them a bit more carefully.
As mentioned in the earlier article, readtables control read-macros which allow the Lisp reader to alter the forms it receives before they are executed or compiled. Important, also, is that those read-macros are not applied to the result of macro expansion. So, what is in the readtable?
From a programming perspective, a readtable can be considered to be a table of functions to invoke when a symbol begins with a specific character. This can further be broken into two categories, dispatching macro characters, and non-dispatching macro characters. A dispatching macro character opens on a second table of characters, defining two-character prefix codes. A non-dispatching macro character has no further sub-character control. You can see an example of the latter case in the article discussing eval-when.
The Common Lisp standard defines a default readtable in which the # character is a dispatching macro character. If the reader encounters that character at the beginning of a symbol, it parses out any decimal number following it, and looks for the first non-digit character that follows. The intercalary number, if any, becomes an argument to the two-character prefix. The readtable is then used to look up that two-character macro and calls the appropriate function with the numeric argument, if any. If no numeric argument is supplied, the value passed to the function for that parameter is nil, not zero.
You’ve encountered the # dispatching macro character many times, but if it isn’t pointed out you might not realize that they’re all just manifestations of the readtable, and act to modify input before it enters the Lisp instance proper. We’ve mentioned #’SYMBOL, which gets translated into (function SYMBOL). Other combinations you’ve probably used include #\ for literal characters, #X for hexadecimal constants, #O for octal constants, and #+ and #- for doing conditional reads.
So, with that introduction, what about get-dispatch-macro-character? This function returns the read macro function that corresponds to the two-character combination, if any. If there is no such sub-character option to the supplied dispatching macro character, it returns nil. If the first argument is not a dispatching macro character, it generates an error.
Then we have set-dispatch-macro-character. Not surprisingly, this sets the function to be invoked when that particular two-character combination is encountered by the reader.
One final note. There is no standard way to unset a dispatch macro character. Typically, one uses copy-readtable to store a copy of the current readtable, makes the appropriate modifications for the purpose, and then restores the readtable from the copy afterwards.