Printable CLOS objects..?

Discussion of Common Lisp
Post Reply
jdavis
Posts: 2
Joined: Sat Jul 26, 2008 2:13 pm

Printable CLOS objects..?

Post by jdavis » Sat Jul 26, 2008 2:23 pm

Hi all,

I've been using Common Lisp for about a year so I'm still a relative newbie. My question is CLOS related. Up until now, I've used structures (through defstruct) heavily but I'm starting to substitute CLOS classes in for structs in certain places. I like the flexibility that CLOS gives me.

However, something that I like about structs is that they can easily be printed in a way that the reader can read them back in. This makes it easy to do simple archival of objects in plain text files. I've noticed recently that CLOS objects do not seem to be printable in the same way (they print with the funky #<> unreadable syntax). Is there any easy way to print CLOS objects in a way that they can be read back in easily?

I won't really need to use multiple inheritance in the near future so maybe structs would be good enough (using single inheritance). I know you can even define generic methods based on struct types. Should I just stick with structs? Should I start using CLOS and roll my own methods for reading and writing objects (or is there some easy way to do it)?

Regards,
Justin

findinglisp
Posts: 447
Joined: Sat Jun 28, 2008 7:49 am
Location: Austin, TX
Contact:

Re: Printable CLOS objects..?

Post by findinglisp » Sat Jul 26, 2008 8:15 pm

There is nothing as generic as that for structs. You can override how CLOS objects print and the output can be essentially anything you want. The issue comes with reading things back in. Depending on your needs, you could do something as simplistic as making the printed version of a "foo" object be:

Code: Select all

(make-instance 'foo :slot1 'slot1-value :slot2 'slot2-value)
You would have to handle any inheritance yourself, whether single or multiple, and arrange to get all the slots there that you would need to recreate an object. Also, that is not the same as a reader macro, which is what structures use. Thus, using READ on the above output would give you back that whole code snippet, not a full CLOS object. You'd have to arrange to have that code executed to generate the object. You could create your own reader macro to essentially do what structures do (the #s syntax) and then call MAKE-INSTANCE under the hood.

Ultimately, CLOS is infinitely more flexible than structures, but there is a cost in complexity. If you know that structures will work for you and you can't foresee that you'll need CLOS right away, I'd go with structures. On the other hand, if you can easily envision that things are going to need to get more complex right away, then CLOS is probably a better solution as it will scale for the long term to incorporate more requirements easily.
Cheers, Dave
Slowly but surely the world is finding Lisp. http://www.findinglisp.com/blog/

Kompottkin
Posts: 94
Joined: Mon Jul 21, 2008 7:26 am
Location: München, Germany
Contact:

Re: Printable CLOS objects..?

Post by Kompottkin » Sun Jul 27, 2008 1:31 am

findinglisp wrote:You can override how CLOS objects print and the output can be essentially anything you want.
Just in case the OP doesn't know how: You can do this by defining a method on print-object.
findinglisp wrote:... Depending on your needs, you could do something as simplistic as making the printed version of a "foo" object be:

Code: Select all

(make-instance 'foo :slot1 'slot1-value :slot2 'slot2-value)
... Thus, using READ on the above output would give you back that whole code snippet, not a full CLOS object. You'd have to arrange to have that code executed to generate the object. You could create your own reader macro to essentially do what structures do (the #s syntax) and then call MAKE-INSTANCE under the hood.
Alternately, you can also arrange for your object to be printed as something like (note the use of the sharp-dot reader macro):

Code: Select all

#.(make-instance 'foo :slot1 'slot1-value :slot2 'slot2-value)
Unfortunately, this needs *read-eval* to be true, so it's dangerous when you're reading stuff from random foreign sources. See http://www.lispworks.com/documentation/ ... 02_dhf.htm for details.

jdavis
Posts: 2
Joined: Sat Jul 26, 2008 2:13 pm

Re: Printable CLOS objects..?

Post by jdavis » Sun Jul 27, 2008 9:59 am

findinglisp wrote: Ultimately, CLOS is infinitely more flexible than structures
Thank you for your replies. I'm sure you're right that CLOS is more flexible but I'm not seeing where the benefits are right now (I've read ACL and PCL). Since structs are still using CLOS under the hood, are "true" classes defined with defclass really that much more flexible? It seems that with structs I can do basic single inheritance and also use generic methods and standard method combination.

The only thing that I can see wouldn't be possible would be multiple inheritance and maybe some other super fancy stuff I probably wouldn't use anyway. Is there any online article you can point me to that would explain in what situations CLOS (or really "defclass" classes) would be the right way to go?

Thanks,
Justin

WeYu
Posts: 9
Joined: Sun Aug 10, 2008 1:14 pm

Re: Printable CLOS objects..?

Post by WeYu » Sun Aug 10, 2008 1:54 pm

jdavis wrote: However, something that I like about structs is that they can easily be printed in a way that the reader can read them back in. This makes it easy to do simple archival of objects in plain text files. I've noticed recently that CLOS objects do not seem to be printable in the same way (they print with the funky #<> unreadable syntax). Is there any easy way to print CLOS objects in a way that they can be read back in easily?
Hi jdavis, here's a quick and dirty example of how to print objects like structs with sbcl. The code hasn't been tested much. If you want to be able to read them back in, try writing a function that turns a plist into an object and replacing print-unreadable-object with (princ "#I") or something, and then fiddling with set-dispatch-macro-character.

Code: Select all

#+sbcl 
(defun class-slots (class-designator)
  (typecase class-designator
    (symbol
     (sb-pcl:class-direct-slots (find-class class-designator)))    
    (standard-object
     (sb-pcl:class-direct-slots (class-of class-designator)))))

#+sbcl
(defun slot-name (slot)
  (sb-pcl:slot-definition-name slot))

(defmethod print-object ((me standard-object) stream)
  (let ((bound-slots-plist
           (loop for i in (class-slots me)
              for name = (slot-name i)
              when (slot-boundp me name)
              collect (intern (string name) :keyword)
              and
              collect (slot-value me name))))
    (if bound-slots-plist
        (print-unreadable-object (me stream :type t :identity t)
          (prin1 bound-slots-plist stream))
        (print-unreadable-object (me stream :type t :identity t)))))

Szymon
Posts: 3
Joined: Fri Aug 01, 2008 1:24 pm
Location: Gdańsk, Poland

Re: Printable CLOS objects..?

Post by Szymon » Thu Aug 14, 2008 12:35 am


Post Reply