Re: SETF for functions returning multiple values.

"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]> Tue, 9 Jun 2026 03:57:09 -0700
Newsgroups gmane.lisp.lispworks.general
Message-ID <[email protected]>
The real trick here, and to keep things totally portable, you have to build your number readers using READ-CHAR. Do not use READ, until you have something you know will be read correctly. 

So if I have a pattern that selects out just the conventional number portion of an extended number syntax, then I can use READ-FROM-STRING on that substring.  And I surround the read with WITH-VANILLA-READTABLE to prevent inadvertent recursion.

Before Pascal showed the way with non-terminating macros, I had been trying to patch over the internal read routines using advice. That took a lot of reverse engineering, and was just waiting to break. And that worked just fine for me until SBCL totally rewrote their reader last year. Then it all broke.

I had to discover that you are only in charge so long as you use READ-CHAR.

- DM

> On Jun 9, 2026, at 03:43, David McClain (as dbm at refined-audiometrics dot com) <[email protected]> wrote:
> 
> 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
>