From: ···@healy.washington.dc.us
Subject: Readable output
Date: 
Message-ID: <87u1s8kvzt.fsf@zotz.local>
I would like to find out a few things about output (printing)
readably.  There are probably several somewhat different questions,
but I view them as related.  

I would like to (optionally) generate objects for readability.  
Suppose I have an object "myobject" that is made with make-myobject,
and I have a reader macro #_ that expands to make-myobject
e.g. #_foo -> (make-myobject foo).  Now for the print-object or
print-function, I can test *print-readably*/*print-escape* and
print "#_foo".  Of course, when read, this expands to the
make-myobject form.  So far so good.

Now if I have a vector of myobjects, it prints
 #(#_foo1 #_foo2 #_foo3)
which is a vector consisting of the lists '(make-myobject foo1) etc.,
which is bad - I want a vector of objects, not a vector of forms that
when evaluated would make them.  How can I do this?
The only thing that comes to mind is "#.".

Second,  suppose I don't have a reader macro #_, or suppose that the
object is too complicated to be read in with the reader macro.  Then
my full, official way of making the object is with (make-myobject ...)
Is it appropriate to have my print method generate the full form?
I have always defined a make-load-form method for this purpose, but of
course that doesn't affect "printing"; should I have the print method
call make-load-form when it attempts to print readably?  Somehow it
seems that generating a sexp as the output for a non-list isn't the
right way to go.  Should it print something like 
 "#.(make-myobject ...)"
?

I'd like to get a sense of the usual practice here.

--
Liam Healy

From: Erik Naggum
Subject: Re: Readable output
Date: 
Message-ID: <3223474979263343@naggum.net>
* ···@healy.washington.dc.us
| Suppose I have an object "myobject" that is made with make-myobject,
| and I have a reader macro #_ that expands to make-myobject
| e.g. #_foo -> (make-myobject foo).

  Reader macros do not "expand".  A reader macro is a function that
  consumes input and returns Common Lisp objects.  Maybe "reader macro" is
  a misnomer and that it should be called "reader function" or something,
  but the historical reason is probably that all sorts of "macro languages"
  were around which allowed special interpretation of "macro characters".
  Some macro characters do indeed "expand", but that is their function, not
  the other way around.  E.g., 'x returns the list (quote x), but (x)
  returns the list (x) and "x" returns the string "x", because ( and " are
  macro characters that construct objects.  ' and #' are very special.

| Now for the print-object or print-function, I can test *print-readably*/
| *print-escape* and print "#_foo".  Of course, when read, this expands to
| the make-myobject form.  So far so good.

  Probably not.  The evaluation time appears to be completely wrong.

| Now if I have a vector of myobjects, it prints #(#_foo1 #_foo2 #_foo3)
| which is a vector consisting of the lists '(make-myobject foo1) etc.,
| which is bad - I want a vector of objects, not a vector of forms that
| when evaluated would make them.

  So it did not work in the above example, either.  #_foo was not read as
  myobject objects, but as a list.  This indicates a massive failure to
  grasp how reader macros work, and you need to retrace your steps back to
  where you thought you learned how to do what you did.  Incidentally, some
  code would make the amount of guesswork on my side a lot less, but I
  guess that you do something like this in your reader function:

    `(make-myobject ,(read ...))

| How can I do this?  The only thing that comes to mind is "#.".

  You could do something like this in your reader function

    (make-myobject (read ...))

| Is it appropriate to have my print method generate the full form?

  Not if *read-eval* is nil and *print-readably* is true.

  It is much better to create reader macros (syntax) for your special
  objects then try to depend on being able to depend on *read-eval*.

  "Unfortunately", there is no general constructor syntax for claseses like
  there is for structures, but you could of course try to create one using
  the same mold.

///
-- 
  In a fight against something, the fight has value, victory has none.
  In a fight for something, the fight is a loss, victory merely relief.
From: Pierre R. Mai
Subject: Re: Readable output
Date: 
Message-ID: <87bsefc2gn.fsf@orion.bln.pmsf.de>
···@healy.washington.dc.us writes:

> I would like to find out a few things about output (printing)
> readably.  There are probably several somewhat different questions,
> but I view them as related.  
> 
> I would like to (optionally) generate objects for readability.  
> Suppose I have an object "myobject" that is made with make-myobject,
> and I have a reader macro #_ that expands to make-myobject
> e.g. #_foo -> (make-myobject foo).  Now for the print-object or
> print-function, I can test *print-readably*/*print-escape* and
> print "#_foo".  Of course, when read, this expands to the
> make-myobject form.  So far so good.

Not really.  Generally reader macros are supposed to return the
created object, not forms that will create the object when evaluated.

E.g. the #\( reader macro will create a list with the given content,
which it returns, it will not return a (list ...) form, which only
creates the object at eval-time.

So your reader macro should be similar to:

(defun |#_-reader| (stream sub-char arg)
  (declare (ignore sub-char arg))
  (let ((content (read stream t t t)))
    (make-myobject content)))

rather than

(defun |#_-reader| (stream sub-char arg)
  (declare (ignore sub-char arg))
  (let ((content (read stream t t t)))
    `(make-myobject ',content)))

as it is probably now.

This will automagically solve your "myobject-inside-vectors" problem.

> Is it appropriate to have my print method generate the full form?
> I have always defined a make-load-form method for this purpose, but of
> course that doesn't affect "printing"; should I have the print method
> call make-load-form when it attempts to print readably?  Somehow it
> seems that generating a sexp as the output for a non-list isn't the
> right way to go.  Should it print something like 
>  "#.(make-myobject ...)"
> ?

If *read-eval* is true at the time of printing, you can use #. to
print out a representation that will result in an appropriate object
being created at read-time.  If *read-eval* is false, and
*print-readably* is true, and you cannot use other means to print out
a representation that will result in an appropriate object being
created at read-time, you'll have to signal an error.

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: ···@healy.washington.dc.us
Subject: Re: Readable output
Date: 
Message-ID: <87g03qbsyg.fsf@zotz.local>
>>>>> "Pierre" == Pierre R Mai <····@acm.org> writes:

    Pierre> ···@healy.washington.dc.us writes:
    >> I would like to find out a few things about output (printing)
    >> readably.  There are probably several somewhat different questions,
    >> but I view them as related.  
    >> 
    >> I would like to (optionally) generate objects for readability.  
    >> Suppose I have an object "myobject" that is made with make-myobject,
    >> and I have a reader macro #_ that expands to make-myobject
    >> e.g. #_foo -> (make-myobject foo).  Now for the print-object or
    >> print-function, I can test *print-readably*/*print-escape* and
    >> print "#_foo".  Of course, when read, this expands to the
    >> make-myobject form.  So far so good.

    Pierre> Not really.  Generally reader macros are supposed to return the
    Pierre> created object, not forms that will create the object when evaluated.

    Pierre> E.g. the #\( reader macro will create a list with the given content,
    Pierre> which it returns, it will not return a (list ...) form, which only
    Pierre> creates the object at eval-time.

    Pierre> So your reader macro should be similar to:

    Pierre> (defun |#_-reader| (stream sub-char arg)
    Pierre>   (declare (ignore sub-char arg))
    Pierre>   (let ((content (read stream t t t)))
    Pierre>     (make-myobject content)))

    Pierre> rather than

    Pierre> (defun |#_-reader| (stream sub-char arg)
    Pierre>   (declare (ignore sub-char arg))
    Pierre>   (let ((content (read stream t t t)))
    Pierre>     `(make-myobject ',content)))

    Pierre> as it is probably now.

    Pierre> This will automagically solve your "myobject-inside-vectors" problem.

Bingo.  That was my error.

    >> Is it appropriate to have my print method generate the full form?
    >> I have always defined a make-load-form method for this purpose, but of
    >> course that doesn't affect "printing"; should I have the print method
    >> call make-load-form when it attempts to print readably?  Somehow it
    >> seems that generating a sexp as the output for a non-list isn't the
    >> right way to go.  Should it print something like 
    >> "#.(make-myobject ...)"
    >> ?

    Pierre> If *read-eval* is true at the time of printing, you can use #. to
    Pierre> print out a representation that will result in an appropriate object
    Pierre> being created at read-time.  If *read-eval* is false, and
    Pierre> *print-readably* is true, and you cannot use other means to print out
    Pierre> a representation that will result in an appropriate object being
    Pierre> created at read-time, you'll have to signal an error.

The use of *read-eval* was a fine point I hadn't considered.

Thanks for the advice.

--
Liam Healy