Re: SETF for functions returning multiple values.

"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]> Tue, 9 Jun 2026 03:43:40 -0700
Newsgroups gmane.lisp.lispworks.general
Message-ID <[email protected]>
The only hitch that I ran into, when making all digits and + and -, into non-terminating macro characters in the readtable - is that when printing out items, the PRINT-OBJECT apparently uses the *READTABLE* to discern when it should insert an escape backslash ahead of every character.

So I grab a plain vanilla copy of a readtable and keep it around for thwarting this ugly result. With an around method (PRINT-OBJECT :AROUND (SYMBOL T)) I do:

————————————————

(defvar *vanilla-readtable* (copy-readtable nil))

(defmacro with-vanilla-readtable (&body body)
  `(let ((*readtable*  *vanilla-readtable*))
     ,@body))

(let (#+:LISPWORKS (lw:*handle-warn-on-redefinition* nil))
  ;; Prevent printouts from using xxx\-\1\2\3 for xxx-123, etc.  ; <- make the digit magic invisible ;-)
  (defmethod print-object :around ((object symbol) out-stream)
    (with-vanilla-readtable
      (call-next-method))))

—————————————————————

Then, just for safety purposes, I ensure that any attempt to modify the *READTABLE* is prevented if it is the vanilla readtable…
 
———————————————————

(defun report-attempt-to-write-vanilla-readtable (rt)
  (when (eq rt *vanilla-readtable*)
    (error "Vanilla Readtable is Read-Only!")))

#+:LISPWORKS
(progn
  (lw:defadvice (set-dispatch-macro-character not-in-vanilla-readtable :before)
      (disp-char sub-char function &optional (readtable *readtable*))
    (declare (ignore disp-char sub-char function))
    (report-attempt-to-write-vanilla-readtable readtable))
  
  (lw:defadvice (set-macro-character not-in-vanilla-readtable :before)
      (char function &optional non-terminating-p (readtable *readtable*))
    (declare (ignore char function non-terminating-p))
    (report-attempt-to-write-vanilla-readtable readtable)))

—————————————————

There is a similar pair of advice for SBCL.

With these patches in place I have not run into any problems from my extended number syntax.

- DM


> On Jun 9, 2026, at 03:17, Madhu (as enometh at meer dot net) <[email protected]> wrote:
> 
> * "David McClain (as dbm at refined-audiometrics dot com)" <[email protected]> :
> Wrote on Mon, 8 Jun 2026 11:13:44 -0700:
>> I made my own digits become macro characters so that I can directly
>> handle numbers written like these:
>> +1°23’.23
>> 2026/06/08T11:10:09U+7
>> 520-234-3474
>> and of course any number can be written with embedded comma or
>> underscore: 1_234.5192_5542_112D0
> 
> Thanks, (I remember this as something I couldn't solve decades ago
> when I tried to use the reader)
> 
> (comment to tfb below)
> 
>> I love it! Lisp no longer feels like a straightjacket to me. I can
>> just directly type in the numbers as I need them.
>> 
>> The only other time in my life where I had such freedom was in my
>> ancient Forth Mount Control Systems on the world’s largest telescopes.
>> 
>>> On Jun 8, 2026, at 11:02, Tim Bradshaw (as tfb at tfeb dot org)
>>> <[email protected]> wrote:
> 
>>> (setf (values p1 p2) <form-returning-two-values>) should work when
>>> p1 and p2 are places (the spec talks about this).
> 
>>> If F is a function returning two values, then you can't write a
>>> (SETF F) function for it, but you can write a setf expansion pretty
>>> easily.  So then you just can say (setf (f ...) (values v1 v2)).
>>> 
>>> I don't think I've seen this done elsewhere.  Does it strike people
>>> as reasonable?
>>> 
>>> The reason I'm asking is that the delimited-string reading thing
>>> I've been cleaning up now lets you control the closing delimiter, so
>>> that for instance #D[foo/bar.ldat] might read as the contents of the
>>> file foo/bar.ldat (ie the opening and closing delimiters are
>>> different now, which they used not to be.
>>> 
>>> The function which lets you set up handlers is get-dsr-handler and
>>> it now returns two values the handler (or NIL) and the closing
>>> delimiter (or NIL if it's the same as the opening delimiter).
>>> 
>>> So I want to be able to say (setf (get-dsr-handler #\[) (values
>>> my-handler #\])) say.
> 
> I'd just use a cons.  My cmucl-init has a read-verbatim-string reader
> with this comment
> 
> ```
> (defvar *matching-delim-pairs* '((#\( . #\)) (#\{ . #\}) (#\[ . #\]))
>    "Alist of (LDELIM . RDELIM) characters, for delimiting strings read by
> VERBATIM-STRING-READER."))
> 
>  (setf (documentation 'verbatim-string-reader 'function) #$<reads
> 	$#X...X, where "..." is read verbatim. X, the first character read is
> 	treated as the delimiter. If *USE-MATCHING-DELIM-PAIRS-P* is non-NIL
> 	(default), look in the alist *MATCHING-DELIM-PAIRS* to find a matching
> 	delimiter, which is then used to terminate reading the string<))
> ```
> 
> (I think I had to set the documentation string in a separate form
> because of I couldn't evaluate the (defun ...) form in emacs -- in
> certain lisps -- if i put it inside the function)
> 
> 
>>> [The actual hidden motivation for this is an utterly perverse usage
>>> I thought of: you can make any digit character be an opening
>>> delimiter and the closing delimiter for all of them be #\., and with
>>> a suitable handler function
>>> 
>>> ? #D1213,456,789.
>>> 1213456789
>>> 
>>> And even
>>> 
>>>> #16DFFFF FF00 ABCD.
>>> 281474959977421
>>> 
>>> So that's pretty neat.]
> 
> _______________________________________________
> Lisp Hug - the mailing list for LispWorks users
> [email protected]
> http://www.lispworks.com/support/lisp-hug.html