Subject: Re: [Q] package-specific dispatch macro character
From: rpw3@rpw3.org (Rob Warnock)
Date: Tue, 23 Sep 2008 21:32:29 -0500
Newsgroups: comp.lang.lisp
Message-ID: <ooadnet9_psgO0TVnZ2dnUVZ_sninZ2d@speakeasy.net>
Kaz Kylheku  <kkylheku@gmail.com> wrote:
+---------------
| Didier Verna <didier@lrde.epita.fr> wrote:
| > I have a package which is ASDF installable and in which I'd like to use
| > a personal dispatch macro character. This particular DMC should be
| > active when the package files are compiled or evaluated (via ASDF, but
| > ideally in other situations), but I don't want to pollute the rest of
| > the lisp session with it.
...
| Note that the functions COMPILE-FILE and LOAD save and restore the
| values of *PACKAGE* and *READ-TABLE*.
+---------------

Ummm, yes, saves/restores [binds, actually] the values of those
*variables*, but *doesn't* save/restore the objects they contain!!
(See below...)

+---------------
| This is why you can have (IN-PACKAGE "MY-PACKAGE") in a file
| without worrying that loading the file will change the current package.
+---------------

True, but IN-PACKAGE effectively just sets CL:*PACKAGE*, it doesn't mess
with the package *itself* which was the former value of CL:*PACKAGE*.

+---------------
| You can take the same liberty in changing the read table near
| the top of your source files.
+---------------

CAREFUL!! You may safely change the CL:*READTABLE* *variable* here,
but *NOT* the readtable it contains!!!

+---------------
| I would do it via read-time evaluation, since the read table
| adjustment is not useful for load time:
| 
|   ;; top of the file
|   ;; ...
|   (in-package :my-package)
|   ;; at read time, hash dot!
|   #.(set-dispatch-macro-character ...)
|   ;; ...
|   ;; bottom of file: package and readtable are restored for us!
+---------------

No, the CL:*PACKAGE* and CL:*READTABLE* *variables* are restored
for us, but the objects they originally contained *aren't*!
CL:*PACKAGE* isn't a problem, since you didn't change the formerly-
referenced package object, but by doing the SET-DISPATCH-MACRO-CHARACTER
you *did* mutate the actual readtable that the CL:*READTABLE* previously
held... and now still currently holds, even after the return to the
compiler/loader! (Oops.)

Thomas Burdick already noted up-thread the right way to do this, but
here's the short-short version [steps #2 & #3 may safely be swapped]:

1. Create a *new* readtable object;
2. Make your mods to *that* readtable; and then
3. Assign that object to the CL:*READTABLE* variable.

So, modifying your template:

    ;; top of the file
    ;; ...
    (in-package :my-package)

    (eval-when (:compile-toplevel :load-toplevel :execute)
      (setf cl:*readtable*
	    (let ((my-rt ((copy-readtable rt))))
	      (flet ((my-func (stream sub-char infix-count)
		       ;; Only if you really do ignore them
		       (declare (ignore sub-char infix-count))
	               ...{your new syntax implemented here}...))
		;; Using "#$" as an example
		(set-dispatch-macro-character #\# #\$ my-func my-rt))
	      my-rt)))
    ;; New syntax now enabled for the rest of the file.

    ;; ...
    ;; bottom of file: package and readtable are restored for us!

The above over-simplified template is really only useful if you have
only *one* file that needs to use the modified syntax and you want
it enabled *everywhere* within that file. Thomas Burdick's version is
better if you need multiple files to use the syntax and/or if you want
to be able to easily turn the syntax on & off within a given file.


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607