From: dstein64
Subject: Structures
Date: 
Message-ID: <c7e4a1ba-8f06-4990-a010-3fa1acbc6143@p25g2000hsf.googlegroups.com>
I've been trying to learn Lisp for a few weeks now. I've read most of
Practical Common Lisp, and noticed that there is no mention of
structures or defstruct. I did not read the sections on CLOS, so I am
assuming that objects can probably achieve all that structures did,
but it seems that a lot of legacy code, and code that I am writing for
my Artificial Intelligence class will use structures.

Is it still common to use structures in common lisp code? Is there any
reason I should avoid them? It seems that some of the newer guides do
not mention them. Thanks!

From: Tayssir John Gabbour
Subject: Re: Structures
Date: 
Message-ID: <53e41611-0fdf-4d55-9021-48b5279e1a5a@d21g2000prf.googlegroups.com>
On Mar 29, 8:31 pm, dstein64 <········@gmail.com> wrote:
> Is it still common to use structures in common lisp code? Is there
> any reason I should avoid them? It seems that some of the newer
> guides do not mention them. Thanks!

My personal experience is that structures are very uncommon. (Maybe
someone has more accurate arguments than I pro/con because they're
just not a serious part of my world.)

However, I use it when dealing with peoples' highly list-oriented
code, where they store info in lists like:

  (name address city state)

and it's horrible because you have to remember what position the
city's supposed to be in or whatever. Structures come to the rescue
because they have this handy feature where a struct can really be a
list:

  CL-USER> (defstruct (location (:type list))
             name address city state)
  LOCATION
  CL-USER> (make-location)
  (NIL NIL NIL NIL)
  CL-USER> (make-location :address 10)
  (NIL 10 NIL NIL)
  CL-USER> (location-name '(1 2 3 4))
  1
  CL-USER> (location-address '(1 2 3 4))
  2


A lot of people don't like OOP, and they will use an old fashioned
list-oriented style like this. Or maybe their IDE doesn't just make
writing defclass instant, so they're lazy. Well, this feature of
structures lets me handle their code without needing to perform
serious surgery.


Tayssir
From: tim
Subject: Re: Structures
Date: 
Message-ID: <13utbhfh0oc0saf@corp.supernews.com>
On Sat, 29 Mar 2008 13:06:23 -0700, Tayssir John Gabbour wrote:

> On Mar 29, 8:31 pm, dstein64 <········@gmail.com> wrote:
>> Is it still common to use structures in common lisp code? Is there
>> any reason I should avoid them? It seems that some of the newer
>> guides do not mention them. Thanks!
> 

I started off using lists for my compiler but eventually I got sick of
remembering that (nth 11 data-item) was level-nbr, etc. Especially I got
sick of forgetting these pieces of information. So I switched to structs to
hold the various parse tree elements. This has worked quite well. 

* Gives fields meaningful names.
* Provides some error checking at run time.

Lisp allows structures to incorporate other structures: "(:include
included-structure-name {slot-description}*)". This is good because all my
grammar structures can share a common header.

On the down side it makes the code more verbose at times. One problem with
completely dynamic typing is that the compiler does not know the types of
data and so you always have to tell it at some cost in tokens you have to
type in. Also defstruct by default names the accessors
[struct-name]-[field-name] which makes for long names.

Another downside is that generic routines that walk trees and lists no
longer work because they don't understand structures. I wrote a structure
walking function that supports a visitor type pattern to get around this.

Tim
From: Ken Tilton
Subject: Re: Structures
Date: 
Message-ID: <47eec0c8$0$15190$607ed4bc@cv.net>
tim wrote:
> On Sat, 29 Mar 2008 13:06:23 -0700, Tayssir John Gabbour wrote:
> 
> 
>>On Mar 29, 8:31 pm, dstein64 <········@gmail.com> wrote:
>>
>>>Is it still common to use structures in common lisp code? Is there
>>>any reason I should avoid them? It seems that some of the newer
>>>guides do not mention them. Thanks!

Structures are fine and much faster than CLOS, go for it. What I find is 
that often I will end up needing something CLOS offers and something 
that starts as a struct eventually becomes a CLOS class.

>>
> 
> I started off using lists for my compiler but eventually I got sick of
> remembering that (nth 11 data-item) was level-nbr, etc. Especially I got
> sick of forgetting these pieces of information. So I switched to structs to
> hold the various parse tree elements. This has worked quite well. 
> 
> * Gives fields meaningful names.
> * Provides some error checking at run time.
> 
> Lisp allows structures to incorporate other structures: "(:include
> included-structure-name {slot-description}*)". This is good because all my
> grammar structures can share a common header.
> 
> On the down side it makes the code more verbose at times. One problem with
> completely dynamic typing is that the compiler does not know the types of
> data and so you always have to tell it at some cost in tokens you have to
> type in. Also defstruct by default names the accessors
> [struct-name]-[field-name] which makes for long names.

Hunh? As you noted, that is merely the default. It is no big deal to 
supply the :conc-name option.

kenny

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: tim
Subject: Re: Structures
Date: 
Message-ID: <13utqif3a8jof7f@corp.supernews.com>
On Sat, 29 Mar 2008 18:20:32 -0400, Ken Tilton wrote:

> tim wrote:
>> On Sat, 29 Mar 2008 13:06:23 -0700, Tayssir John Gabbour wrote:
> Hunh? As you noted, that is merely the default. It is no big deal to 
> supply the :conc-name option.
> 
> kenny
>

The language has a spec of 1,000 pages and a huge number of productions.
Some structures can be reused across multiple productions but many can't.
So there are many structures and many fields. Also if overriding one needs
to check that the name is not a duplicate, used elsewhere, which is more
work.

(* trivial large)
=> large

With objects it might not be so large a job because generic
functions get built that can be shared (same name) across many different
classes. 

I haven't used this because I am concerned about speed of execution,
without much evidence I admit.

Tim
From: Ken Tilton
Subject: Re: Structures
Date: 
Message-ID: <47eef7f0$0$15183$607ed4bc@cv.net>
tim wrote:
> On Sat, 29 Mar 2008 18:20:32 -0400, Ken Tilton wrote:
> 
> 
>>tim wrote:
>>
>>>On Sat, 29 Mar 2008 13:06:23 -0700, Tayssir John Gabbour wrote:
>>
>>Hunh? As you noted, that is merely the default. It is no big deal to 
>>supply the :conc-name option.
>>
>>kenny
>>
> 
> 
> The language has a spec of 1,000 pages and a huge number of productions.
> Some structures can be reused across multiple productions but many can't.
> So there are many structures and many fields. Also if overriding one needs
> to check that the name is not a duplicate, used elsewhere, which is more
> work.
> 
> (* trivial large)
> => large
> 
> With objects it might not be so large a job because generic
> functions get built that can be shared (same name) across many different
> classes. 

Nice speech, bad assumption: what makes you think I was going to supply 
the value nil along with the :conc-name option? Or did I guess wrong at 
the point you were making? You never quite made it explicit, but it 
sounded as if you were concerned about name clashes.

Allow me to abbreviate the confusion:

   (defstruct (newsgroup (:conc-name ng-))
      name address messages)

As for performance, CLOS is not slow, structs are just much faster. The 
argument against premature optimization is not one in favor of seeing a 
high-performance situation and deliberately using something slower than 
necessary. So if someone happens to have a need to allocate a kazillion 
thingys, their only problem is coming up with an abbreviateion for 
thingy when they use defstruct. I would go with th-.

hth, kenny

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: tim
Subject: Premature optimization (was Re: Structures
Date: 
Message-ID: <13uu9fvjn0h1sc7@corp.supernews.com>
On Sat, 29 Mar 2008 22:15:52 -0400, Ken Tilton wrote:

> Nice speech, bad assumption: what makes you think I was going to supply 
> the value nil along with the :conc-name option? Or did I guess wrong at 
> the point you were making? You never quite made it explicit, but it 
> sounded as if you were concerned about name clashes.
> 
> Allow me to abbreviate the confusion:
> 
>    (defstruct (newsgroup (:conc-name ng-))
>       name address messages)

I thought in that case I may as well just make the structure names short
as define the :conc-name. It's not really that big a deal. I just
mentioned it as one downside of using structs vs objects.

Optimization
************

A few people have mentioned premature optimization. This is something I
have to fight against, having grown up in a world where CPU time cost over
$1.50 per second and disk space was $30/mb/month. I just don't yet have a
good sense of what is going to get me in trouble later and what is not.

Last month I spent two days restructuring my code so it would be easy to
split it into multiple threads (using SBCL threads). I felt if I left it
until later I would have more code to fix up later on. Still not sure that
was a good investment at that stage.

How do other people manage these dilemmas?

Tim
From: danb
Subject: Re: Premature optimization (was Re: Structures
Date: 
Message-ID: <a9393395-9319-4851-b603-403145f10c12@d45g2000hsc.googlegroups.com>
tim wrote:
> Optimization
> I just don't yet have a good sense of what is
> going to get me in trouble later and what is not.
> How do other people manage these dilemmas?

For threads, try to minimize data sharing.  Don't
iterate anywhere you can map.  Even iteration can
sometimes be faked by generating a list of integers
and mapping onto that.

For premature optimization, don't worry about
getting in trouble.  Just get the program working
however you can, and profile it if it's too slow.
If you find yourself obsessing over low-level
performance issues, find something better to
obsess over.  Try to improve the overall design,
or find more interesting projects to work on
if that's an option.

--Dan

------------------------------------------------
Dan Bensen
http://www.prairienet.org/~dsb/
From: Kent M Pitman
Subject: Re: Structures
Date: 
Message-ID: <u7iflxg51.fsf@nhplace.com>
dstein64 <········@gmail.com> writes:

> I've been trying to learn Lisp for a few weeks now. I've read most of
> Practical Common Lisp, and noticed that there is no mention of
> structures or defstruct. I did not read the sections on CLOS, so I am
> assuming that objects can probably achieve all that structures did,
> but it seems that a lot of legacy code, and code that I am writing for
> my Artificial Intelligence class will use structures.
> 
> Is it still common to use structures in common lisp code? Is there any
> reason I should avoid them? It seems that some of the newer guides do
> not mention them. Thanks!

I recommend using classes always (even though they are sometimes
slower, depending on circumstance and implementation) and optimizing
your code once you get to the point that you have a deliverable
application that is not acceptably fast because of its speed, and
where replacing the class with a struct will fix that.

In other words, I don't think the difference in speed of structs
(which is sometimes noticeable, but again depending on situation) is
worth the flexibility cost, and I think that many people prematurely
optimize these things in a way that inhibits their ability to think
about problems usefully.

Often, in the end, one doesn't need the full power of [standard]
classes.  But one might.  And if you put an obstacle in your path (by
having things implemented initially as structs), the barrier to using
the full features of classes is often the revamping of a bunch of
stupid syntax, such that you might avoid it when you shouldn't.  It's
better to focus on optimization when it's known that it will matter.

So many applications are thrown away before they are ever deployed,
and not for reasons of speed, that I just don't think it matters.
From: Pascal Bourguignon
Subject: Re: Structures
Date: 
Message-ID: <874papp5eg.fsf@thalassa.informatimago.com>
dstein64 <········@gmail.com> writes:

> I've been trying to learn Lisp for a few weeks now. I've read most of
> Practical Common Lisp, and noticed that there is no mention of
> structures or defstruct. I did not read the sections on CLOS, so I am
> assuming that objects can probably achieve all that structures did,
> but it seems that a lot of legacy code, and code that I am writing for
> my Artificial Intelligence class will use structures.
>
> Is it still common to use structures in common lisp code? 

Yes.  But perhaps more in Q&D exploratory code than in production code.

> Is there any reason I should avoid them? 

No reason whatsoever.  On the contrary, they even might be slightly
more efficient than CLOS objects.

> It seems that some of the newer guides do
> not mention them. Thanks!

What you can do with structures you cannot with CLOS objects:

You can use lists or vectors to store your data, and define a
structure to access the fields.

That is, it's very practical to be able to define literal data such as:

(defparameter *db* '(("Bart" "Simpson" "Skateboard")
                     ("Lisa" "Simpson" "Microscope")
                     ("Wendy" "Darling" "Doll")))

(defstruct (child (:type list)) first-name surname toy)

(dolist (child *db*)
   (format t "~A likes to play with a ~(~A~).~%" 
             (child-first-name child)
             (child-toy child)))

Bart likes to play with a skateboard.
Lisa likes to play with a microscope.
Wendy likes to play with a doll.


Which is much better than:

(dolist (child *db*)
   (format t "~A likes to play with a ~(~A~).~%" 
             (car child) (caddr child)))



(defparameter *pentagon* '( #(0 0 0)
                            #(1 0 0)
                            #(1 1 0)
                            #(0 1 0)
                            #(0.3 1.3) ))

(defstruct (point (:type vector) x y z))
(dolist (point *pentagon*) 
   (draw-point (point-x point) (point-y point)))


Even for normal structures, defstruct may be more practical than defclass:

(defstruct employee first-name surname address salary)

vs.

(defclass employee ()
   ((first-name :accessor employee-first-name :initarg :first-name :initform nil)
    (surname    :accessor employee-surname    :initarg :surname    :initform nil)
    (address    :accessor employee-address    :initarg :address    :initform nil)
    (salary     :accessor employee-salary     :initarg :salary     :initform nil)))
(defmethod print-object ((self employee) stream)
  (format stream "#S(~S :FIRST-NAME ~S :SURNAME ~S :ADDRESS ~S :SALARY ~S)"
     (employee-first-name self)
     (employee-surname self)
     (employee-address self)
     (employee-salary self))
  self)
(defmethod copy-employee ((self employee))
  (make-instance 'employee 
       :first-name (employee-first-name self)
       :surname    (employee-surname self)
       :address    (employee-address self)
       :salary     (employee-salary self)))
(defun make-employee (&rest args)
  (apply (function make-instance) 'employee args))
(defun employeep (object) (typep object 'employee))
;; ...


So you can understand that when you want to stay in the flow, you'll
rather use defstruct than defclass...

defstruct can even do simple inheritance, by inclusion of fields of a
"super-struct".




So defstruct has certainly its uses.  But as your application grows,
often you will switch from defstruct to defclass when you start
needing the features only CLOS provides.  The right thing to do, is to
start with your own macro, that can expand to defstruct at first, and
when your application grows, you switch to defclass.

(defmacro defentity (name ...) ... `(progn (defstruct ...) ...))

Often, when you define various application specific structures or
objects, you define at the same time a few other functions or methods,
so it's natural to use a macro already.  After all, lists, vectors,
structures or objects, they're CS notions, not application domain
notions.  Nobody cares about which is used.  So you should abstract
them away, and hide them in application level macros.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

PLEASE NOTE: Some quantum physics theories suggest that when the
consumer is not directly observing this product, it may cease to
exist or will exist only in a vague and undetermined state.
From: Vassil Nikolov
Subject: Re: Structures
Date: 
Message-ID: <snz3an3qwj9.fsf@luna.vassil.nikolov.name>
On Sat, 29 Mar 2008 12:31:53 -0700 (PDT), dstein64 <········@gmail.com> said:
| ...
| objects can probably achieve all that structures did

  Even though it applies to relatively few cases, it is worth noting
  that structures are the only standard facility (in Common Lisp) that
  allows user-defined types [*] with a readable print syntax.  In
  other words, a structure is the thing when the programmer wants the
  lisp reader itself, and with just the standard readtable, to produce
  typed values from literals.  A structure may have just one slot, of
  course, like in (EQUALP #S(APPLES :$ 17) #S(ORANGES :$ 17)).

  Structure types can be used with generic function dispatch, of
  course, so one wouldn't have to change DEFMETHOD signatures if
  switching from structures to classes.

  BOA-constructors are nice, too.

  [*] that work with CHECK-TYPE, TYPECASE, TYPEP without the need of
      an extra DEFTYPE with a SATISFIES definition

  ---Vassil.


-- 
Peius melius est.  ---Ricardus Gabriel.
From: Russell McManus
Subject: Re: Structures
Date: 
Message-ID: <87iqvzgd18.fsf@thelonious.cl-user.org>
Vassil Nikolov <···············@pobox.com> writes:

> Even though it applies to relatively few cases, it is worth noting
> that structures are the only standard facility (in Common Lisp) that
> allows user-defined types [*] with a readable print syntax.  In
> other words, a structure is the thing when the programmer wants the
> lisp reader itself, and with just the standard readtable, to produce
> typed values from literals.  A structure may have just one slot, of
> course, like in (EQUALP #S(APPLES :$ 17) #S(ORANGES :$ 17)).

It is possible to use defclass to define types with a readable print
syntax.  Here is some example code:

(in-package :cl-user)

(defclass point () 
  ((x :initarg :x :reader get-x)
   (y :initarg :y :reader get-y)))

(defmethod print-object ((point point) stream)
  (format stream "#.~S" `(make-instance 'point 
					:x ,(get-x point)
					:y ,(get-y point))))

(let* ((p1 (make-instance 'point :x 1 :y 2))
       (s (with-output-to-string (s) (format s "~S" p1)))
       (p2 (read-from-string s)))
  (values (get-x p2) (get-y p2)))
From: Barry Margolin
Subject: Re: Structures
Date: 
Message-ID: <barmar-76DD4E.15045624062008@newsgroups.comcast.net>
In article <··············@thelonious.cl-user.org>,
 Russell McManus <···············@yahoo.com> wrote:

> Vassil Nikolov <···············@pobox.com> writes:
> 
> > Even though it applies to relatively few cases, it is worth noting
> > that structures are the only standard facility (in Common Lisp) that
> > allows user-defined types [*] with a readable print syntax.  In
> > other words, a structure is the thing when the programmer wants the
> > lisp reader itself, and with just the standard readtable, to produce
> > typed values from literals.  A structure may have just one slot, of
> > course, like in (EQUALP #S(APPLES :$ 17) #S(ORANGES :$ 17)).
> 
> It is possible to use defclass to define types with a readable print
> syntax.  Here is some example code:
> 
> (in-package :cl-user)
> 
> (defclass point () 
>   ((x :initarg :x :reader get-x)
>    (y :initarg :y :reader get-y)))
> 
> (defmethod print-object ((point point) stream)
>   (format stream "#.~S" `(make-instance 'point 
> 					:x ,(get-x point)
> 					:y ,(get-y point))))

True, but sharpsign-dot is a really gross hack that one should rarely 
depend on.  Safety-conscious programmers will disable it when reading 
from external sources, because it allows anything to happen in the 
context of reading.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Pascal Costanza
Subject: Re: Structures
Date: 
Message-ID: <6cd4suF3gm4etU3@mid.individual.net>
Barry Margolin wrote:
> In article <··············@thelonious.cl-user.org>,
>  Russell McManus <···············@yahoo.com> wrote:
> 
>> Vassil Nikolov <···············@pobox.com> writes:
>>
>>> Even though it applies to relatively few cases, it is worth noting
>>> that structures are the only standard facility (in Common Lisp) that
>>> allows user-defined types [*] with a readable print syntax.  In
>>> other words, a structure is the thing when the programmer wants the
>>> lisp reader itself, and with just the standard readtable, to produce
>>> typed values from literals.  A structure may have just one slot, of
>>> course, like in (EQUALP #S(APPLES :$ 17) #S(ORANGES :$ 17)).
>> It is possible to use defclass to define types with a readable print
>> syntax.  Here is some example code:
>>
>> (in-package :cl-user)
>>
>> (defclass point () 
>>   ((x :initarg :x :reader get-x)
>>    (y :initarg :y :reader get-y)))
>>
>> (defmethod print-object ((point point) stream)
>>   (format stream "#.~S" `(make-instance 'point 
>> 					:x ,(get-x point)
>> 					:y ,(get-y point))))
> 
> True, but sharpsign-dot is a really gross hack that one should rarely 
> depend on.  Safety-conscious programmers will disable it when reading 
> from external sources, because it allows anything to happen in the 
> context of reading.

Yes, that too.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: Structures
Date: 
Message-ID: <6ccd3rF3epk4hU1@mid.individual.net>
Russell McManus wrote:
> Vassil Nikolov <···············@pobox.com> writes:
> 
>> Even though it applies to relatively few cases, it is worth noting
>> that structures are the only standard facility (in Common Lisp) that
>> allows user-defined types [*] with a readable print syntax.  In
>> other words, a structure is the thing when the programmer wants the
>> lisp reader itself, and with just the standard readtable, to produce
>> typed values from literals.  A structure may have just one slot, of
>> course, like in (EQUALP #S(APPLES :$ 17) #S(ORANGES :$ 17)).
> 
> It is possible to use defclass to define types with a readable print
> syntax.  Here is some example code:
> 
> (in-package :cl-user)
> 
> (defclass point () 
>   ((x :initarg :x :reader get-x)
>    (y :initarg :y :reader get-y)))
> 
> (defmethod print-object ((point point) stream)
>   (format stream "#.~S" `(make-instance 'point 
> 					:x ,(get-x point)
> 					:y ,(get-y point))))
> 
> (let* ((p1 (make-instance 'point :x 1 :y 2))
>        (s (with-output-to-string (s) (format s "~S" p1)))
>        (p2 (read-from-string s)))
>   (values (get-x p2) (get-y p2)))

Not quite. It's almost impossible to define a readable syntax for CLOS 
objects when they are part of circular structures. That's trivial for 
struct instances, because there it comes for free.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Russell McManus
Subject: Re: Structures
Date: 
Message-ID: <87ej6mhcky.fsf@thelonious.cl-user.org>
Pascal Costanza <··@p-cos.net> writes:

>> It is possible to use defclass to define types with a readable print
>> syntax.  Here is some example code:
>>
>> (in-package :cl-user)
>>
>> (defclass point ()   ((x :initarg :x :reader get-x)
>>    (y :initarg :y :reader get-y)))
>>
>> (defmethod print-object ((point point) stream)
>>   (format stream "#.~S" `(make-instance 'point
>> :x ,(get-x point)
>> 					:y ,(get-y point))))
>>
>> (let* ((p1 (make-instance 'point :x 1 :y 2))
>>        (s (with-output-to-string (s) (format s "~S" p1)))
>>        (p2 (read-from-string s)))
>>   (values (get-x p2) (get-y p2)))
>
> Not quite. It's almost impossible to define a readable syntax for CLOS
> objects when they are part of circular structures. That's trivial for
> struct instances, because there it comes for free.

Interesting.  I just tried the below, and it seemed to work.  

Clearly I'm missing something.  Would you be willing to describe the
problem in more detail?

(defclass parent ()
  ((child :initarg :child :reader get-child)))

(defmethod print-object ((parent parent) stream)
  (format stream "#.~S" `(make-instance 'parent 
					:child ,(get-child parent))))

(defclass child ()
  ((parent :initarg :parent :reader get-parent)))

(defmethod print-object ((child child) stream)
  (format stream "#.~S" `(make-instance 'child 
					:parent ,(get-parent child))))

(let* ((*print-circle* t)
       (parent (make-instance 'parent))
       (child (make-instance 'child :parent parent)))
  (setf (slot-value parent 'child) child)
  child)

-russ
From: Pascal Costanza
Subject: Re: Structures
Date: 
Message-ID: <6cd4rcF3gm4etU2@mid.individual.net>
Russell McManus wrote:

> I just tried the below, and it seemed to work.  
> 
> Clearly I'm missing something.  Would you be willing to describe the
> problem in more detail?
> 
> (defclass parent ()
>   ((child :initarg :child :reader get-child)))
> 
> (defmethod print-object ((parent parent) stream)
>   (format stream "#.~S" `(make-instance 'parent 
> 					:child ,(get-child parent))))
> 
> (defclass child ()
>   ((parent :initarg :parent :reader get-parent)))
> 
> (defmethod print-object ((child child) stream)
>   (format stream "#.~S" `(make-instance 'child 
> 					:parent ,(get-parent child))))
> 
> (let* ((*print-circle* t)
>        (parent (make-instance 'parent))
>        (child (make-instance 'child :parent parent)))
>   (setf (slot-value parent 'child) child)
>   child)

Sure, the printing works. But did you try to actually read the result? ;)

The problem here is that there is a mismatch between the different read 
times:

#1=(... #.(... #1# ...))

The Lisp reader attempts to resolve the #1# reference at a time where 
the #1= label doesn't exist yet.

I don't know of any way how to get around this for CLOS classes (which 
is a pity).


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: Structures
Date: 
Message-ID: <6cd538F3gm4etU4@mid.individual.net>
Pascal Costanza wrote:
> Russell McManus wrote:
> 
>> I just tried the below, and it seemed to work. 
>> Clearly I'm missing something.  Would you be willing to describe the
>> problem in more detail?
>>
>> (defclass parent ()
>>   ((child :initarg :child :reader get-child)))
>>
>> (defmethod print-object ((parent parent) stream)
>>   (format stream "#.~S" `(make-instance 'parent                     
>> :child ,(get-child parent))))
>>
>> (defclass child ()
>>   ((parent :initarg :parent :reader get-parent)))
>>
>> (defmethod print-object ((child child) stream)
>>   (format stream "#.~S" `(make-instance 'child                     
>> :parent ,(get-parent child))))
>>
>> (let* ((*print-circle* t)
>>        (parent (make-instance 'parent))
>>        (child (make-instance 'child :parent parent)))
>>   (setf (slot-value parent 'child) child)
>>   child)
> 
> Sure, the printing works. But did you try to actually read the result? ;)
> 
> The problem here is that there is a mismatch between the different read 
> times:
> 
> #1=(... #.(... #1# ...))
> 
> The Lisp reader attempts to resolve the #1# reference at a time where 
> the #1= label doesn't exist yet.
> 
> I don't know of any way how to get around this for CLOS classes (which 
> is a pity).

...well maybe there is a way to define a CLOS metaclass that stores 
slots in embedded structs, which may enable the reuse of the built-in 
mechanism for dealing with circular struct instances. But there may be 
some other unresolvable issues lurking around. Hard to tell without 
trying it.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Russell McManus
Subject: Re: Structures
Date: 
Message-ID: <871w2mgzr5.fsf@thelonious.cl-user.org>
Pascal Costanza <··@p-cos.net> writes:

>> The Lisp reader attempts to resolve the #1# reference at a time
>> where the #1= label doesn't exist yet.
>>
>> I don't know of any way how to get around this for CLOS classes
>> (which is a pity).

Thanks for the explanation.  Perhaps the reader should be extensible
in this direction.  It's hard to imagine that the reader can be
extended in so many ways, but not in this way.

I've often thought that CL should have a *reader* variable which would
be kind of like *debugger-hook*, so that the user could portably
replace the reader.  It would make it possible to retrofit this kind
of functionality into any cl.  I haven't thought through the myriad
issues, of course...

-russ
From: Richard M Kreuter
Subject: Re: Structures
Date: 
Message-ID: <874p7hpekj.fsf@progn.net>
Russell McManus <···············@yahoo.com> writes:

> I've often thought that CL should have a *reader* variable which would
> be kind of like *debugger-hook*, so that the user could portably
> replace the reader.

One venerable way to do this is to have a readtable in which every
character is associated with a read-macro that calls into a custom
parser.

--
RmK
From: Russell McManus
Subject: Re: Structures
Date: 
Message-ID: <87od5ofio7.fsf@thelonious.cl-user.org>
Richard M Kreuter <·······@progn.net> writes:

> Russell McManus <···············@yahoo.com> writes:
>
>> I've often thought that CL should have a *reader* variable which would
>> be kind of like *debugger-hook*, so that the user could portably
>> replace the reader.
>
> One venerable way to do this is to have a readtable in which every
> character is associated with a read-macro that calls into a custom
> parser.

Yeah, I remembered this trick after I posted, but I guess I hid that
neuron on purpose earlier.

-russ
From: Didier Verna
Subject: Re: Structures
Date: 
Message-ID: <muxlk0tj3ny.fsf@uzeb.lrde.epita.fr>
Russell McManus <···············@yahoo.com> wrote:

> (defclass parent ()
>   ((child :initarg :child :reader get-child)))
>
> (defmethod print-object ((parent parent) stream)
>   (format stream "#.~S" `(make-instance 'parent 
> 					:child ,(get-child parent))))
>
> (defclass child ()
>   ((parent :initarg :parent :reader get-parent)))
>
> (defmethod print-object ((child child) stream)
>   (format stream "#.~S" `(make-instance 'child 
> 					:parent ,(get-parent child))))
>
> (let* ((*print-circle* t)
>        (parent (make-instance 'parent))
>        (child (make-instance 'child :parent parent)))
>   (setf (slot-value parent 'child) child)
>   child)

    This exhausts the stack for me. Actually, this doesn't work either:

CL-USER> (defstruct parent (child))
PARENT
CL-USER> (defstruct child (parent))
CHILD
CL-USER> (let* ((*print-circle* t)
		(parent (make-parent))
		(child (make-child :parent parent)))
	   (setf (parent-child parent) child)
	   child)
; Evaluation aborted.


And now, I'm totally confused... I must be missing something obvious.

-- 
5th European Lisp Workshop at ECOOP 2008, July 7: http://elw.bknr.net/2008/

Didier Verna, ······@lrde.epita.fr, http://www.lrde.epita.fr/~didier

EPITA / LRDE, 14-16 rue Voltaire   Tel.+33 (0)1 44 08 01 85
94276 Le Kremlin-Bic�tre, France   Fax.+33 (0)1 53 14 59 22  ······@xemacs.org
From: Pascal J. Bourguignon
Subject: Re: Structures
Date: 
Message-ID: <7cd4m5n73i.fsf@pbourguignon.anevia.com>
Didier Verna <······@lrde.epita.fr> writes:

> Russell McManus <···············@yahoo.com> wrote:
>
>> (defclass parent ()
>>   ((child :initarg :child :reader get-child)))
>>
>> (defmethod print-object ((parent parent) stream)
>>   (format stream "#.~S" `(make-instance 'parent 
>> 					:child ,(get-child parent))))
>>
>> (defclass child ()
>>   ((parent :initarg :parent :reader get-parent)))
>>
>> (defmethod print-object ((child child) stream)
>>   (format stream "#.~S" `(make-instance 'child 
>> 					:parent ,(get-parent child))))
>>
>> (let* ((*print-circle* t)
>>        (parent (make-instance 'parent))
>>        (child (make-instance 'child :parent parent)))
>>   (setf (slot-value parent 'child) child)
>>   child)
>
>     This exhausts the stack for me. Actually, this doesn't work either:
>
> CL-USER> (defstruct parent (child))
> PARENT
> CL-USER> (defstruct child (parent))
> CHILD
> CL-USER> (let* ((*print-circle* t)
> 		(parent (make-parent))
> 		(child (make-child :parent parent)))
> 	   (setf (parent-child parent) child)
> 	   child)
> ; Evaluation aborted.
>
>
> And now, I'm totally confused... I must be missing something obvious.

Yes.  When the PRINT in the REPL wants to print the result of your LET
form, the binding to *PRINT-CICLE* will have been restored.

Either:

(setf *print-circle* t)
(let* ((parent (make-parent))
       (child (make-child :parent parent)))
   (setf (parent-child parent) child)
   child)


or:

(let* ((*print-circle* t)
 	   (parent (make-parent))
       (child (make-child :parent parent)))
    (setf (parent-child parent) child)
    (print child)
    (values))


Vivement les vacances!



-- 
__Pascal Bourguignon__
From: Didier Verna
Subject: Re: Structures
Date: 
Message-ID: <muxprq5hgsz.fsf@uzeb.lrde.epita.fr>
···@informatimago.com (Pascal J. Bourguignon) wrote:

> Yes. When the PRINT in the REPL wants to print the result of your LET
> form, the binding to *PRINT-CICLE* will have been restored.

  Doh! Oh boy, I need to get some sleep...

> Vivement les vacances!

  Tu m'�tonnes ! ;-)

-- 
5th European Lisp Workshop at ECOOP 2008, July 7: http://elw.bknr.net/2008/

Didier Verna, ······@lrde.epita.fr, http://www.lrde.epita.fr/~didier

EPITA / LRDE, 14-16 rue Voltaire   Tel.+33 (0)1 44 08 01 85
94276 Le Kremlin-Bic�tre, France   Fax.+33 (0)1 53 14 59 22  ······@xemacs.org
From: John Thingstad
Subject: Re: Structures
Date: 
Message-ID: <op.uda07tiyut4oq5@pandora.alfanett.no>
>
> Vivement les vacances!
>
>
>

Et tu Pascal!

--------------
John Thingstad
From: Parth Malwankar
Subject: Re: Structures
Date: 
Message-ID: <f0690486-8f89-4001-8cbe-ab3a4ce3751c@i36g2000prf.googlegroups.com>
On Jun 24, 7:02 pm, Pascal Costanza <····@p-cos.net> wrote:
> Russell McManus wrote:
> > Vassil Nikolov <···············@pobox.com> writes:
>
> >> Even though it applies to relatively few cases, it is worth noting
> >> that structures are the only standard facility (in Common Lisp) that
> >> allows user-defined types [*] with a readable print syntax.  In
> >> other words, a structure is the thing when the programmer wants the
> >> lisp reader itself, and with just the standard readtable, to produce
> >> typed values from literals.  A structure may have just one slot, of
> >> course, like in (EQUALP #S(APPLES :$ 17) #S(ORANGES :$ 17)).
>
> > It is possible to use defclass to define types with a readable print
> > syntax.  Here is some example code:
>
> > (in-package :cl-user)
>
> > (defclass point ()
> >   ((x :initarg :x :reader get-x)
> >    (y :initarg :y :reader get-y)))
>
> > (defmethod print-object ((point point) stream)
> >   (format stream "#.~S" `(make-instance 'point
> >                                    :x ,(get-x point)
> >                                    :y ,(get-y point))))
>
> > (let* ((p1 (make-instance 'point :x 1 :y 2))
> >        (s (with-output-to-string (s) (format s "~S" p1)))
> >        (p2 (read-from-string s)))
> >   (values (get-x p2) (get-y p2)))
>
> Not quite. It's almost impossible to define a readable syntax for CLOS
> objects when they are part of circular structures. That's trivial for
> struct instances, because there it comes for free.
>
> Pascal
>
> --
> My website:http://p-cos.net
> Common Lisp Document Repository:http://cdr.eurolisp.org
> Closer to MOP & ContextL:http://common-lisp.net/project/closer/

In my limited experience with lisp (I am still quite new) I found
structures
to be quite convenient to use. I get read/write support, predicate
checking,
attribute access, inheritance, method specialization all for free.

'defstruct ...' declarations are much shorter than 'defclass ...' but
this wasn't that big an issue as its trivial to create your own
'defklass ...'
macro which expands to 'defclass ...'.

Doing a little bit of reading I found that structures are nothing but
a specialized class in Common Lisp.


    [3]> (defclass a () ((x)))
    #<STANDARD-CLASS A>
    [4]> (defstruct b ())
    B

    [7]> (class-of (make-b))
    #<STRUCTURE-CLASS B>
    [8]> (class-of (class-of (make-b)))
    #<STANDARD-CLASS STRUCTURE-CLASS>
    [9]>

As per my understanding, classes are useful:
 - when you want to add slots or change class at runtime
 - use multiple inheritance

In case all the slots are known at design time and single inheritance
suffices, is it might make sense to use structures.

Would appreciate comments in case I have missed out some other
advantages
of classes.

Thanks.
Parth
From: Rainer Joswig
Subject: Re: Structures
Date: 
Message-ID: <joswig-33E6E8.09264426062008@news-europe.giganews.com>
In article 
<····································@i36g2000prf.googlegroups.com>,
 Parth Malwankar <···············@gmail.com> wrote:

> On Jun 24, 7:02 pm, Pascal Costanza <····@p-cos.net> wrote:
> > Russell McManus wrote:
> > > Vassil Nikolov <···············@pobox.com> writes:
> >
> > >> Even though it applies to relatively few cases, it is worth noting
> > >> that structures are the only standard facility (in Common Lisp) that
> > >> allows user-defined types [*] with a readable print syntax.  In
> > >> other words, a structure is the thing when the programmer wants the
> > >> lisp reader itself, and with just the standard readtable, to produce
> > >> typed values from literals.  A structure may have just one slot, of
> > >> course, like in (EQUALP #S(APPLES :$ 17) #S(ORANGES :$ 17)).
> >
> > > It is possible to use defclass to define types with a readable print
> > > syntax.  Here is some example code:
> >
> > > (in-package :cl-user)
> >
> > > (defclass point ()
> > >   ((x :initarg :x :reader get-x)
> > >    (y :initarg :y :reader get-y)))
> >
> > > (defmethod print-object ((point point) stream)
> > >   (format stream "#.~S" `(make-instance 'point
> > >                                    :x ,(get-x point)
> > >                                    :y ,(get-y point))))
> >
> > > (let* ((p1 (make-instance 'point :x 1 :y 2))
> > >        (s (with-output-to-string (s) (format s "~S" p1)))
> > >        (p2 (read-from-string s)))
> > >   (values (get-x p2) (get-y p2)))
> >
> > Not quite. It's almost impossible to define a readable syntax for CLOS
> > objects when they are part of circular structures. That's trivial for
> > struct instances, because there it comes for free.
> >
> > Pascal
> >
> > --
> > My website:http://p-cos.net
> > Common Lisp Document Repository:http://cdr.eurolisp.org
> > Closer to MOP & ContextL:http://common-lisp.net/project/closer/
> 
> In my limited experience with lisp (I am still quite new) I found
> structures
> to be quite convenient to use. I get read/write support, predicate
> checking,
> attribute access, inheritance, method specialization all for free.
> 
> 'defstruct ...' declarations are much shorter than 'defclass ...' but
> this wasn't that big an issue as its trivial to create your own
> 'defklass ...'
> macro which expands to 'defclass ...'.

Which has been done before. For example in the original CLX
implementation one can decide to create classes or structures
for all the X11 objects before compile time.

> 
> Doing a little bit of reading I found that structures are nothing but
> a specialized class in Common Lisp.

Well, the first version of Common Lisp (described in CLtL1) had
no CLOS (-> no classes and no generic functions). CLOS
had been added later and when CLOS was added the question
of classes for existing types came up. So Common Lisp has
now also classes for some non-CLOS types. For example
there is a class for the type NUMBER, but not for (integer 3 5).
The classes have been added so that generic functions can
also dispatch on some non-CLOS data objects. Thus one can
dispatch over NUMBER but not (integer 3 5).

> 
> 
>     [3]> (defclass a () ((x)))
>     #<STANDARD-CLASS A>
>     [4]> (defstruct b ())
>     B
> 
>     [7]> (class-of (make-b))
>     #<STRUCTURE-CLASS B>
>     [8]> (class-of (class-of (make-b)))
>     #<STANDARD-CLASS STRUCTURE-CLASS>
>     [9]>
> 
> As per my understanding, classes are useful:
>  - when you want to add slots or change class at runtime
>  - use multiple inheritance
> 
> In case all the slots are known at design time and single inheritance
> suffices, is it might make sense to use structures.
> 
> Would appreciate comments in case I have missed out some other
> advantages
> of classes.

CLOS has the MOP (Meta-Object Protocol). With its functionality
one can look inside classes and objects (Introspection).
Also the CLOS MOP allows changing/extending the way CLOS works.
So it is possible to get information about the slots in a class.
It is possible write different slot-allocation strategies
(think database, sparse slots, ...).

The drawbacks of CLOS has made users ask their vendors for
added functionality. So various Common Lisp implementations
add some features to improve slot access time (say, sealed classes).
STRUCTURES usually have faster access, since slot positions are
known at compile time. CLOS implementations have been adding
such a feature.

For style guide one can also define:

* use CLOS by default (when there is a choice between structures and classes).
* use structures only when portable faster slot access is necessary.

Classes have also some other features:

* class slots
* classes can be defined before the superclasses
* classes have a metaclass
* there is a single function to make instances: make-instance

For the bigger picture of CLOS, it is best to read AMOP
('The Art of the Metaobject Protocol') which truely
is an excellent book which gives all kinds of enlightenment.

> 
> Thanks.
> Parth

-- 
http://lispm.dyndns.org/
From: Thomas A. Russ
Subject: Re: Structures
Date: 
Message-ID: <ymi3an05fh6.fsf@blackcat.isi.edu>
Parth Malwankar <···············@gmail.com> writes:

> Would appreciate comments in case I have missed out some other
> advantages of classes.

Well, in a large system there is the additional advantage that the
accessors associated with classes are generic functions.  With
structures, they are ordinary functions, which means that you have to be
careful to make sure that the names are distinct.

Now, the default behavior of structs helps with this by building slot
accessor names by prepending the structure name.  But when used together
with inheritance, this leads to a mix of access styles that requires you
to be aware of the level of slot you want:

    (person-name s1)
    (student-takes-classes s1)
    (animal-species s1)

assuming some sort of simple   animal>person>student hierarchy


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Costanza
Subject: Re: Structures
Date: 
Message-ID: <6ci456F3gsfi4U1@mid.individual.net>
Thomas A. Russ wrote:
> Parth Malwankar <···············@gmail.com> writes:
> 
>> Would appreciate comments in case I have missed out some other
>> advantages of classes.
> 
> Well, in a large system there is the additional advantage that the
> accessors associated with classes are generic functions.  With
> structures, they are ordinary functions, which means that you have to be
> careful to make sure that the names are distinct.
> 
> Now, the default behavior of structs helps with this by building slot
> accessor names by prepending the structure name.  But when used together
> with inheritance, this leads to a mix of access styles that requires you
> to be aware of the level of slot you want:
> 
>     (person-name s1)
>     (student-takes-classes s1)
>     (animal-species s1)
> 
> assuming some sort of simple   animal>person>student hierarchy

That can be changed with the conc-name option in defstruct.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Marco Antoniotti
Subject: Re: Structures
Date: 
Message-ID: <17fd60d5-959e-43dd-a451-31ce3e9e64f0@34g2000hsh.googlegroups.com>
On Jun 26, 8:06 pm, Pascal Costanza <····@p-cos.net> wrote:
> Thomas A. Russ wrote:
> > Parth Malwankar <···············@gmail.com> writes:
>
> >> Would appreciate comments in case I have missed out some other
> >> advantages of classes.
>
> > Well, in a large system there is the additional advantage that the
> > accessors associated with classes are generic functions.  With
> > structures, they are ordinary functions, which means that you have to be
> > careful to make sure that the names are distinct.
>
> > Now, the default behavior of structs helps with this by building slot
> > accessor names by prepending the structure name.  But when used together
> > with inheritance, this leads to a mix of access styles that requires you
> > to be aware of the level of slot you want:
>
> >     (person-name s1)
> >     (student-takes-classes s1)
> >     (animal-species s1)
>
> > assuming some sort of simple   animal>person>student hierarchy
>
> That can be changed with the conc-name option in defstruct.
>

Yes.  But note also that in TAR's example

    (student-species s1)

will work.

Cheers
--
Marco
From: Thomas A. Russ
Subject: Re: Structures
Date: 
Message-ID: <ymir6ai4q6u.fsf@blackcat.isi.edu>
Marco Antoniotti <·······@gmail.com> writes:

> On Jun 26, 8:06��pm, Pascal Costanza <····@p-cos.net> wrote:
> > Thomas A. Russ wrote:
> > > �� �� (person-name s1)
> > > �� �� (student-takes-classes s1)
> > > �� �� (animal-species s1)
> >
> > > assuming some sort of simple �� animal>person>student hierarchy
> >
> > That can be changed with the conc-name option in defstruct.
> >
> 
> Yes.  But note also that in TAR's example
> 
>     (student-species s1)
> 
> will work.

Wow.  Learn something new every day.  I didn't realize that struct
inclusion resulted in the generation of new accessors for all of the
inherited slots.

That actually makes something we have been doing a bit easier!

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Costanza
Subject: Re: Structures
Date: 
Message-ID: <6cgv21F3g5eovU1@mid.individual.net>
Parth Malwankar wrote:

> As per my understanding, classes are useful:
>  - when you want to add slots or change class at runtime
>  - use multiple inheritance
> 
> In case all the slots are known at design time and single inheritance
> suffices, is it might make sense to use structures.
> 
> Would appreciate comments in case I have missed out some other
> advantages of classes.

Slots of classes can be unbound, which can be a very useful feature.

Slot accessors are generic functions, and you can define 
before/after/around (and even primary) methods on slot accessors.

Instances of classes can change their class at runtime.

You have a distinction between instance slots and class slots (not that 
useful though).

You can define default initargs in classes (sometimes useful).

Classes have a well-defined metaobject protocol (for implementations 
that support the CLOS MOP). That part of the CLOS MOP is the best 
understood, most widely supported and most useful one.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Vassil Nikolov
Subject: Re: Structures
Date: 
Message-ID: <snzy74up11x.fsf@luna.vassil.nikolov.name>
On Tue, 24 Jun 2008 08:47:47 -0500, Russell McManus <···············@yahoo.com> said:
| It is possible to use defclass to define types with a readable print
| syntax.  Here is some example code:
| ...
| (defmethod print-object ((point point) stream)
|   (format stream "#.~S" `(make-instance 'point 
| 					:x ,(get-x point)
| 					:y ,(get-y point))))

  Independently of the sharpsign-dot matter, I think it is important
  that with structures, the printability comes "for free", without any
  extra effort by the programmer.  Even when this effort is not too
  painful, it has a cost not only in the work to do it, but also in
  its fragility, since it is only up to the programmer to update it
  whenever the class definition(s) change(s).  (Or in the work to
  automate the latter, which does not seem particularly easy.)

  Now, when we know that we'll be using some kind of values a lot,
  we'll also know it is worth to implement a character macro syntax
  for it, but for rarely used values, or in the exploratory phase, we
  may prefer self-descriptive literals to plain strings, for a little
  extra robustness or readability at low cost.  For example, if we
  have

    (defun find-location (city &optional street) ...)

  we might prefer

    (find-location #s(city :$ sofia) #s(street :$ paris))  ;[1, 2]

  to

    (find-location 'sofia 'paris)  ;makes us wonder if someone forgot
                                   ; to erase a value being replaced

  We can still easily allow the latter as well e.g. for interactive
  use.  For example, whereever we only work with the strings (e.g. for
  database access), we can write ($ CITY) and ($ STREET) instead of
  just CITY and STREET, with something like

    (defgeneric $ (x) (:documentation "Produce the namestring of the argument."))
    (defmethod $ ((x city)) (string (city-$ x)))
    (defmethod $ ((x street)) (string (street-$ x)))
    (defmethod $ ((x string)) x)
    (defmethod $ ((x symbol)) (string x))

  Again, this is not library-grade code, but "optimized" for
  exploration, to get us going quickly while still allowing some
  measure of "tagging" what is going on.  Once the design will have
  crystallized, `$' can just be redefined (possibly as a macro) if
  there will be any of the prototype code left that will not have been
  rewritten.

  _________
  [1] This is not equivalent to

        (find-location :city 'sofia :street 'paris)

      since we want the values to be tagged, not just the arguments.
      So when a value gets printed, we know what it is without having
      to write any code ourselves to give us the type.

  [2] Or

        (find-location #s(city :$ paris) #s(street :$ sofia))

      if you prefer Lutetia to Serdica.


  ---Vassil.


-- 
Peius melius est.  ---Ricardus Gabriel.
From: Marco Antoniotti
Subject: Re: Structures
Date: 
Message-ID: <c665593f-3099-4872-b8f3-bfdd05ddd845@a1g2000hsb.googlegroups.com>
On Jun 25, 6:54 am, Vassil Nikolov <···············@pobox.com> wrote:
> On Tue, 24 Jun 2008 08:47:47 -0500, Russell McManus <···············@yahoo.com> said:
> | It is possible to use defclass to define types with a readable print
> | syntax.  Here is some example code:
> | ...
> | (defmethod print-object ((point point) stream)
> |   (format stream "#.~S" `(make-instance 'point
> |                                       :x ,(get-x point)
> |                                       :y ,(get-y point))))
>
>   Independently of the sharpsign-dot matter, I think it is important
>   that with structures, the printability comes "for free", without any
>   extra effort by the programmer.  Even when this effort is not too
>   painful, it has a cost not only in the work to do it, but also in
>   its fragility, since it is only up to the programmer to update it
>   whenever the class definition(s) change(s).  (Or in the work to
>   automate the latter, which does not seem particularly easy.)
>
>   Now, when we know that we'll be using some kind of values a lot,
>   we'll also know it is worth to implement a character macro syntax
>   for it, but for rarely used values, or in the exploratory phase, we
>   may prefer self-descriptive literals to plain strings, for a little
>   extra robustness or readability at low cost.  For example, if we
>   have
>
>     (defun find-location (city &optional street) ...)
>
>   we might prefer
>
>     (find-location #s(city :$ sofia) #s(street :$ paris))  ;[1, 2]
>
>   to
>
>     (find-location 'sofia 'paris)  ;makes us wonder if someone forgot
>                                    ; to erase a value being replaced
>
>   We can still easily allow the latter as well e.g. for interactive
>   use.  For example, whereever we only work with the strings (e.g. for
>   database access), we can write ($ CITY) and ($ STREET) instead of
>   just CITY and STREET, with something like
>
>     (defgeneric $ (x) (:documentation "Produce the namestring of the argument."))
>     (defmethod $ ((x city)) (string (city-$ x)))
>     (defmethod $ ((x street)) (string (street-$ x)))
>     (defmethod $ ((x string)) x)
>     (defmethod $ ((x symbol)) (string x))
>
>   Again, this is not library-grade code, but "optimized" for
>   exploration, to get us going quickly while still allowing some
>   measure of "tagging" what is going on.  Once the design will have
>   crystallized, `$' can just be redefined (possibly as a macro) if
>   there will be any of the prototype code left that will not have been
>   rewritten.
>
>   _________
>   [1] This is not equivalent to
>
>         (find-location :city 'sofia :street 'paris)
>
>       since we want the values to be tagged, not just the arguments.
>       So when a value gets printed, we know what it is without having
>       to write any code ourselves to give us the type.
>
>   [2] Or
>
>         (find-location #s(city :$ paris) #s(street :$ sofia))
>
>       if you prefer Lutetia to Serdica.


... and it is not equivalent to

   (use-package "UNIFY") ; As in CL-UNIFICATION http://common-lisp.net/project/cl-unification/

   (find-location #T(city city-name 'paris) #T(street street-name
'sofia))

Which already works portably (provided you write an appropriate FIND-
LOCATION which takes two UNIFY:STRUCTURE-OBJECT-TEMPLATE

Cheers
--
Marco







>
>   ---Vassil.
>
> --
> Peius melius est.  ---Ricardus Gabriel.