From: John Flynn
Subject: Beginner's CLOS questions
Date: 
Message-ID: <nUrJ6.2261$ZJ.85308@ozemail.com.au>
I'm looking into CLOS for the first time. It looks radically different from
any object systems I've seen before, and I'm looking forward to getting a
handle on it. Unfortunately I don't have much reference material or sample
code, so I haven't seen any practical CLOS techniques in action.

I have a few basic questions:

1. Object Construction:

I can't find a way to _enforce_ the creation of an instance through an
explicit constructor, rather than with (make-instance 'class-name). Is there
a way to do this, or is it conventional to supply a constructor of the form
(make-whatever) and trust that it's used?

I'd like to ensure proper initialisation of slot values before the instance
is used. I suppose that's what :initform is for, but I'm having a few
problems with initform. Eg. I can't see how to access slot-value X from
inside the initform of Y where X and Y are slots of the same class. (This
might sound ridiculous, but CLOS is different from what I'm accustomed to).

2. Constant / "Static" Slots:

(a) (How) can I access a slot value with :class allocation without creating
an instance of the class? I've tried (slot-value (find-class 'class-name)
'slot-name), among other things, but I can't figure it out.

(b) Can I define slots with :allocation :class, in such a way that I can
access them from the initforms of the class's other slots?

3. Copying by value:

How can I copy an object field by field, (by value, not by reference), as
with copy-structure? Do I need to copy each field explicitly, or is there
some kind of generic "clone" function? (If so, I couldn't find it in the
Hyperspec).

Any suggestions would be appreciated.
Thanks.

From: Kent M Pitman
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <sfwd79lmq9d.fsf@world.std.com>
"John Flynn" <··········@yahoo.com.au> writes:

> I can't find a way to _enforce_ the creation of an instance through an
> explicit constructor, rather than with (make-instance 'class-name).

Well, it's possible you're just confused about the need for this (see below).

I don't think there is such a way, but you could do something like:

 (defvar *in-make-foo* nil)

 (defclass foo () ())

 (defmethod initialize-instance :around ((foo foo) &key)
   (cond (*in-make-foo* 
	  (let ((*in-make-foo* nil)) ;make sure recursive calls do this anew
	    (call-next-method)))     ;continue initializing
 	 (t
          (error "You used (MAKE-INSTANCE 'FOO) instead of (MAKE-FOO)."))))

 (defun make-foo (&key ...)
   (let ((*in-make-foo* t))
     ...))

> Is there
> a way to do this, or is it conventional to supply a constructor of the form
> (make-whatever) and trust that it's used?
 
It's conventional to make sure initialization works.  
Use :initform for things that can be independently initialized.
Use initialize-instance (or sometimes shared-initialize) methods 
for things that are dependent on other init state; 
often you'll want the :after daemon method on initialize-instance.

> I'd like to ensure proper initialisation of slot values before the instance
> is used. I suppose that's what :initform is for, but I'm having a few
> problems with initform. Eg. I can't see how to access slot-value X from
> inside the initform of Y where X and Y are slots of the same class. (This
> might sound ridiculous, but CLOS is different from what I'm accustomed to).

The initform will get independent values set up.  Then you can bootstrap
the other values in your initialize-instance method. e.g.,

 (defclass foo ()
   ((length :initarg :length :accessor foo-length :initform 0)
    (width  :initarg :width  :accessor foo-width  :initform 0)
    (area                    :accessor foo-area)))

 (defmethod initialize-instance :after ((foo foo) &key)
   (with-slots (length width area) foo
     (setq area (* length width))))

 (defmethod (setf length) :after (new-length (foo foo))
   (declare (ignore new-length)) ;method runs after length slot is set
   (with-slots (length width area) foo
     (setq area (* length width))))

 (defmethod (setf length) :after (new-width (foo foo))
   (declare (ignore new-width)) ;method runs after width slot is set
   (with-slots (length width area) foo
     (setq area (* length width))))

Of course, you might not even want area to be an instance variable at all.
You could just make it a method and this wouldn't come up. e.g.,

 (defclass foo ()
   ((length :initarg :length :accessor foo-length :initform 0)
    (width  :initarg :width  :accessor foo-width  :initform 0)))

 (defmethod area ((foo foo))
   (setq area (* length width)))

> 2. Constant / "Static" Slots:
> 
> (a) (How) can I access a slot value with :class allocation without creating
> an instance of the class?

Without the MOP (which is not part of the standard), you can't.
I don't have a copy of AMOP [The Art of the Meta-Object Protocol] handy
so can't say.  maybe someone else will answer this.  But for ANSI CL
code, it's not something one does.

In general, I'm not a fan of the way :class allocation is done in CL,
and I tell people it's bad style to use it at all.   Usually it does
the wrong thing.  It's a pity CL didn't implement what Dylan calls
"each subclass" allocation.  That would have been a lot more useful.
The problem is that you're sharing this slot with all your subclasses,
and it's too hard to predict what will happen in a lot of cases.

> (b) Can I define slots with :allocation :class, in such a way that I can
> access them from the initforms of the class's other slots?

No, but not for the reason you may think.  Your problem is that initforms are
run before an object is created.  What you want is to put such initializations
in an ``initialize-instance :after'' method.  Within such a method, you can
use with-slots on the instance, and it will let you see class slots the same
as instance slots.  Just be careful about the sharing problems in class slots.
I really recommend avoiding class slots.  Others may disagree with me on this.
What's an example of your use of class slots?

> 3. Copying by value:
> 
> How can I copy an object field by field, (by value, not by reference), as
> with copy-structure? Do I need to copy each field explicitly, or is there
> some kind of generic "clone" function? (If so, I couldn't find it in the
> Hyperspec).

You should write a per-class method to do what methods you want to do.
Just doing field by field copy, as you call it, is not going to work in
general.  e.g., what if the object is something where one of the slots
is maintained as a tail of another.  A copy of the tail is not going to do.

The problem of general-purpose copy is very similar to the problem of 
general-purpose equal. see my article on equality in
 http://world.std.com/~pitman/PS/EQUAL.html
From: Bob Bane
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <3AF6CFBC.8CD2E8@removeme.gst.com>
Kent M Pitman wrote:
> 
> In general, I'm not a fan of the way :class allocation is done in CL,
> and I tell people it's bad style to use it at all.   Usually it does
> the wrong thing.  It's a pity CL didn't implement what Dylan calls
> "each subclass" allocation.  That would have been a lot more useful.
> The problem is that you're sharing this slot with all your subclasses,
> and it's too hard to predict what will happen in a lot of cases.
> 
I've often wanted something like "each subclass" allocation.  Has anyone
tried to do this using the MOP?
-- 
Remove obvious stuff to e-mail me.
Bob Bane
From: Shannon Spires
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <svspire-C4F9F2.14430307052001@news.sandia.gov>
In article <···············@removeme.gst.com>, Bob Bane 
<····@removeme.gst.com> wrote:

> Kent M Pitman wrote:
> > 
> > In general, I'm not a fan of the way :class allocation is done in CL,
> > and I tell people it's bad style to use it at all.   Usually it does
> > the wrong thing.  It's a pity CL didn't implement what Dylan calls
> > "each subclass" allocation.  That would have been a lot more useful.
> > The problem is that you're sharing this slot with all your subclasses,
> > and it's too hard to predict what will happen in a lot of cases.
> > 
> I've often wanted something like "each subclass" allocation.  Has anyone
> tried to do this using the MOP?

One way to do "each subclass" allocation is to just restate the
class-allocated slot each time:

(defclass foo ()
  ((slot1 :initarg :slot1 :initform 1 :accessor slot1 :allocation :class)
   (slot2 :initarg :slot2 :initform nil :accessor slot2)))

(defclass moo (foo)
  ((slot1 :initarg :slot1 :initform 2 :accessor slot1 :allocation 
:class)))

(slot1 (make-instance 'foo)) --> 1
(slot1 (make-instance 'moo)) --> 2

Is it elegant? No. But it does the job.

By the way, to get the value of a class-allocated slot without an
instance of the class (sort of), use #'class-prototype:
(slot1 (class-prototype (find-class 'foo))) --> 1

Caveats: class-prototype is a MOP function, not ANSI. So it might
not be present in all implementations. And because it (technically)
creates an instance, your class hierarchy has to be finalizable or
it won't work. This can be a drawback in some circumstances.

Example:

(defclass bad (boo)
  ((slot1 :initarg :slot1 :initform 1 :accessor slot1 :allocation :class)
   (slot2 :initarg :slot2 :initform nil :accessor slot2)))

(class-prototype (find-class 'bad)) --> error, because boo doesn't exist

Can you access a class-allocated slot without creating any kind of
instance at all? No. Not even with the MOP, unless you're willing
to write some _highly_ implementation-specific code.

Another way to do "each subclass" allocation is to just create a new slot
on a class metaobject:

(defclass my-metaclass (standard-class)
  ((special-slot :initarg :special-slot :initform .1 :accessor 
special-slot)))
 
[Note that special-slot is _not_ class-allocated here. It's 
instance-allocated on class metaobjects.]

(defclass fee ()
  (slot1 slot2)
  (:metaclass my-metaclass))

(defclass gee (fee)
  ()
  (:metaclass my-metaclass))

(special-slot (find-class 'fee)) --> 0.1

(special-slot (find-class 'gee)) --> 0.1

(special-slot (make-instance 'fee)) --> error. Undefined method. Must       
access the slot from a class.
(special-slot (class-of (make-instance 'fee))) --> 0.1 [See below]

(setf (special-slot (find-class 'gee)) 0.2)
(special-slot (find-class 'gee)) --> 0.2
(special-slot (find-class 'fee)) --> 0.1

Some advantages of the "special metaclass" approach are:

1) It makes the shared value a little less accessible to the
instances, since it's not a property of the instances, but of their
class. Which makes it less likely that one instance will change the
value with a global side effect.

2) The class hierarchy doesn't need to be finalizable to see or
change the value. You access the value from a class metaobject, not
from instances thereof.

3) It doesn't depend on the MOP.

4) You can use this special metaclass with classes that are not
even part of the same inheritance hierarchy, if you need to. And
you can have some classes within a hierarchy that have the special
slot, and others that don't. This isn't really possible with
class-allocated slots. This also means you can use this mechanism
to easily create special classes at runtime (e.g. using
ensure-class), when you don't know at compile time which ones need
to have the special slot and which don't. (NOTE: ensure-class is 
a MOP function).

(Exercise: what would have happened if we'd combined the two approaches--
making special-slot in my-metaclass be class-allocated? Can you think
of a use for such a beast?)

Drawbacks of this approach:

1) It makes the shared value a little less accessible to the
instances. If you _do_ want to access the value from an instance,
you have to do it like this: 
(special-slot (class-of <some-instance-of-fee>))
But you can just write a method that does this for you.

2) You have to type :metaclass a lot, or create a special defclass
macro to type it for you.

3) You might not be able to redefine a class later on to "get rid"
of the special slot, if you decide you don't need it any more but
you have extant instances. With class-allocated slots, you can just
re-run defclass without the class-allocated slot, or you can re-run
it with the class-allocated slot changed to be instance-allocated.
But if you use the special metaclass mechanism, you might have
trouble doing this because some implementations restrict the use of
change-class on class metaobjects.

Shannon Spires
·······@remove-this.nmia.com
From: John Flynn
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <tJvJ6.2459$ZJ.90487@ozemail.com.au>
"Kent M Pitman" <······@world.std.com> wrote in message
····················@world.std.com...
> "John Flynn" <··········@yahoo.com.au> writes:
>
> > I can't find a way to _enforce_ the creation of an instance through an
> > explicit constructor, rather than with (make-instance 'class-name).
>
> Well, it's possible you're just confused about the need for this (see
below).

You're right. I thought I needed a "constructor" for situations in which the
initialisation of certain slots depends on the values of other slots. I
wanted this initialisation code to be called automatically when
make-instance (or some other standard construction method I don't know
about) is invoked. The problem is, I didn't know of the existence of
"initialize-instance"  ;-)

[...]

> Use :initform for things that can be independently initialized.
> Use initialize-instance (or sometimes shared-initialize) methods
> for things that are dependent on other init state;
> often you'll want the :after daemon method on initialize-instance.

Thanks. That pretty much covers what I needed to know about initialisation.

> > 2. Constant / "Static" Slots:
> >
> > (a) (How) can I access a slot value with :class allocation without
creating
> > an instance of the class?
>
> Without the MOP (which is not part of the standard), you can't. [...]

OK. Not a big deal.

It's a bit early for me to be delving into black magic, but just as an
aside, how important is the MOP for the effective use of CLOS? I guess it's
hard to generalise (and I have only the vaguest idea of what the MOP
actually is). I can see obvious uses of metaclass information for tool
makers, but beyond that, what are some common uses of the MOP?

[...]

> I really recommend avoiding class slots.  Others may disagree with me on
this.
> What's an example of your use of class slots?

I have no genuine need for them.

When I read that :allocation :class is an option, I thought class slots
would correspond roughly to static data members in C++ or Java, so I tried
them out to see if they work the same way. Similar, but not quite the same.

I'd only be interested in using them when a very large number of instances
contain (or reference) exactly the same piece of data, and/or when changes
to this piece of data must apply to every instance. Eg. bank account
interest rate.

> > 3. Copying by value:
> >
> > How can I copy an object field by field, (by value, not by reference),
as
> > with copy-structure? Do I need to copy each field explicitly, or is
there
> > some kind of generic "clone" function? (If so, I couldn't find it in the
> > Hyperspec).
>
> You should write a per-class method to do what methods you want to do.
> Just doing field by field copy, as you call it, is not going to work in
> general.  e.g., what if the object is something where one of the slots
> is maintained as a tail of another.  A copy of the tail is not going to
do.

Fair enough.

> The problem of general-purpose copy is very similar to the problem of
> general-purpose equal. see my article on equality in
>  http://world.std.com/~pitman/PS/EQUAL.html

Thanks very much for this, Kent. It's been a big help.
From: Kent M Pitman
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <sfwk83tmcl4.fsf@world.std.com>
"John Flynn" <··········@yahoo.com.au> writes:

> When I read that :allocation :class is an option, I thought class slots
> would correspond roughly to static data members in C++ or Java, so I tried
> them out to see if they work the same way. Similar, but not quite the same.
> 
> I'd only be interested in using them when a very large number of instances
> contain (or reference) exactly the same piece of data, and/or when changes
> to this piece of data must apply to every instance. Eg. bank account
> interest rate.

A lot of time it works out fine to just make the right conceptual layout
(as you would with an SQL schema diagram) and you find out this isn't 
needed. Make an instance of bank.

Let it have an interest rate.  Give an account a pointer to the bank.
Make a method on account that just calls the method on the associated
bank.  It's true that this is probably slightly slower than a class
instance, but if you get to the point that this is the performance
bottleneck making or breaking you company's business, I'm sure you'll
be able to work it out. Most people obsess over small constant factor
optimizations to the point they never end up writing an application
important or robust enough to get them far enough that this microspeed
issue matters.

Incidentally, most banks have more than one rate, so here's how you
might structure it to get started:

 (defclass bank ()
   ((id :initarg :id :accessor id)
    (savings-rate  :initarg :savings-rate :accessor savings-rate :initform 0.0)
    (checking-rate :initarg ...)
    (home-mortgage-rate ...)
    (cd-6-month-rate ...)
    ...))

 (defmethod make-account ((bank ...) (kind (eql :savings)))
   (make-instance 'savings-account :bank bank))

 (defmethod make-account ((bank ...) (kind (eql :checking)))
   (make-instance 'checking-account :bank bank))

 (defclass account ()
   ((bank    :initarg :bank    :accessor bank)
    (id      :initarg :id      :accessor id)
    (balance :initarg :balance :accessor balance :initform 0.0)))

 (defgeneric rate (account))

 (defmethod initialize-instance :after ((account account) &key)
   ;; check for required slots 
   (unless (slot-boundp account 'bank) 
     (error "Account ~S has no bank." account))
   ...)

 (defmethod print-object ((account account) stream)
   (with-slots (bank id balance) account
     (print-unreadable-object (account stream :type t :identity t)
       (format stream "~D-~D balance=$~$ rate=~D%"
	       (id bank) id balance (rate account)))))

 (defclass savings-account (account) ())

 (defmethod rate ((account account))
   (savings-rate (bank account)))

 (defclass checking-account (account) ())

 (defmethod rate ((account account))
   (checking-rate (bank account)))

 ...etc.

In the above, the bank has the rate for various kinds of accounts and
the ability to do (make-account my-bank :savings) => #<savings-account>.
The (eql xxx) method specializer you see above is allowing an instance
to substitute for a class in the dispatch; as you can see, you can have
multiple of these.  (I chose these examples to give you some fun stuff
to look up.)
The class account is what java would call an abstract class though CL
has no way to declare that.  It's missing a method on rate.  I usually
"declare" it by putting a defgeneric for the missing functionality at 
the point where the method would be, though this is optional.

By the way, floating point is a terrible representation for money, but
suffices for the example.  If you were going to do a bank, I'd probably
use integer multiples of whatever fraction of a penny you wanted to be
accurate to and shift the value for display.  Lisp has arbitrary precision
integers, but its floating point is just IEEE floating point like most
other languages.

I assume you've found the Common Lisp HyperSpec.
  http://www.xanalys.com/software_tools/reference/HyperSpec/FrontMatter/
It has the language definition, and you can find out about a lot of
things from there, including examples.  You can even download your own
local copy from
  http://www.xanalys.com/software_tools/reference/HyperSpec/

Have fun.
From: Paolo Amoroso
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <Huj2Ogwx7L9iz4WRyw1DnzBPZ6xI@4ax.com>
On Mon, 7 May 2001 14:57:11 GMT, Kent M Pitman <······@world.std.com>
wrote:

>  (defclass savings-account (account) ())

>  (defmethod rate ((account account))
>    (savings-rate (bank account)))

>  (defclass checking-account (account) ())

>  (defmethod rate ((account account))
>    (checking-rate (bank account)))

Shouldn't the lambda lists of the above methods be (account
savings-account) and (account checking-account)?


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/
From: Kent M Pitman
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <sfw1ypzdxr6.fsf@world.std.com>
Paolo Amoroso <·······@mclink.it> writes:

> 
> On Mon, 7 May 2001 14:57:11 GMT, Kent M Pitman <······@world.std.com>
> wrote:
> 
> >  (defclass savings-account (account) ())
> 
> >  (defmethod rate ((account account))
> >    (savings-rate (bank account)))
> 
> >  (defclass checking-account (account) ())
> 
> >  (defmethod rate ((account account))
> >    (checking-rate (bank account)))
> 
> Shouldn't the lambda lists of the above methods be (account
> savings-account) and (account checking-account)?

Yeah. Sorry. Was just sketching, and you're finding paste-o's.
From: Rob Warnock
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <9dags1$6ohlv$1@fido.engr.sgi.com>
Kent M Pitman  <······@world.std.com> wrote:
+---------------
| Yeah. Sorry. Was just sketching, and you're finding paste-o's.
+---------------

ROTFL!!  "Paste-o's"??  Is that what's left
after the mice finish eating the typos?  ;-}

Cheery-Oh!


-Rob

-----
Rob Warnock, 31-2-510		····@sgi.com
SGI Network Engineering		<URL:http://reality.sgi.com/rpw3/>
1600 Amphitheatre Pkwy.		Phone: 650-933-1673
Mountain View, CA  94043	PP-ASEL-IA
From: Tim Moore
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <9d6k6u$eai$0@216.39.145.192>
On Mon, 7 May 2001, John Flynn wrote:
> > Without the MOP (which is not part of the standard), you can't. [...]
> 
> OK. Not a big deal.
> 
> It's a bit early for me to be delving into black magic, but just as an
> aside, how important is the MOP for the effective use of CLOS? I guess it's
> hard to generalise (and I have only the vaguest idea of what the MOP
> actually is). I can see obvious uses of metaclass information for tool
> makers, but beyond that, what are some common uses of the MOP?

If you never use the MOP or think about the MOP, you're left with a
powerful, flexible, kick-ass object system; you're not limited vis-a-vis
any other object system (unless prototype-based languages like Self are
your bag).  However, once you know about it you'll start thinking of uses
for it and want to use it.  A simple use of the MOP would be to write a
print-object method that prints all the bound slots of an instance.  With
the MOP, you can write one method that iterates over the slots of an
instance.  Without the MOP you have to write a method per class (I think)
or wrap defclass with your own macro (not that there's anything wrong with
that).  More complex uses of the MOP include simulating older object
systems with different inheritance rules, allocating instance slots
differently from the standard way (e.g., lazily, in hash table, etc.)....

Tim
From: Paolo Amoroso
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <FKT2Oh26geE51+ksJIjn2Li4=fxi@4ax.com>
On Mon, 7 May 2001 21:48:02 +1000, "John Flynn" <··········@yahoo.com.au>
wrote:

> It's a bit early for me to be delving into black magic, but just as an
> aside, how important is the MOP for the effective use of CLOS? I guess it's
> hard to generalise (and I have only the vaguest idea of what the MOP
> actually is). I can see obvious uses of metaclass information for tool
> makers, but beyond that, what are some common uses of the MOP?

This is a useful introductory resource on MetaObject Protocols:

  Open Implementations and MetaObject Protocols

http://www.parc.xerox.com/spl/groups/eca/pubs/papers/Kiczales-TUT95/for-web.pdf

I personally think that this is a fascinating reading.


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/
From: Janis Dzerins
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <87wv7t5u43.fsf@asaka.latnet.lv>
"John Flynn" <··········@yahoo.com.au> writes:

> I'm looking into CLOS for the first time. It looks radically different from
> any object systems I've seen before, and I'm looking forward to getting a
> handle on it. Unfortunately I don't have much reference material or sample
> code, so I haven't seen any practical CLOS techniques in action.

"Object-Oriented Programming in Common Lisp: A Programmer's Guide to
CLOS" by Sonya E. Keene is quite a nice book to start. It would also
be very helpful to loose any prejudices about OOP you may have
acquired from other languages.

For detailed description and specific questions consult HyperSpec:
http://www.xanalys.com/software_tools/reference/HyperSpec/Body/chap-7.html

> I have a few basic questions:
> 
> 1. Object Construction:
> 
> I can't find a way to _enforce_ the creation of an instance through an
> explicit constructor, rather than with (make-instance 'class-name).

If you need an explicit constructor then you'll have to write one.

> Is there a way to do this, or is it conventional to supply a
> constructor of the form (make-whatever) and trust that it's used?

Yes, it is a common practice. And it is used together with Common Lisp
package system -- one usually exports only symbols which are a part of
external interface. That does not forbid one to use make-instance,
though (also this can also be achieved through a little trickery).

> I'd like to ensure proper initialisation of slot values before the instance
> is used.

There's a method named INITIALIZE-INSTANCE (see HyperSpec).

> I suppose that's what :initform is for, but I'm having a few
> problems with initform.

Initforms are for giving slots default values if they are not supplied
explicitly.

> Eg. I can't see how to access slot-value X from inside the initform
> of Y where X and Y are slots of the same class. (This might sound
> ridiculous, but CLOS is different from what I'm accustomed to).

It will help you to forget for a while what you're accustomed to.

> 2. Constant / "Static" Slots:
> 
> (a) (How) can I access a slot value with :class allocation without creating
> an instance of the class? I've tried (slot-value (find-class 'class-name)
> 'slot-name), among other things, but I can't figure it out.

This I cannot comment on but as far as I remember it can be done using
MOP and is implementation-specific (just don't take my word for it).

> (b) Can I define slots with :allocation :class, in such a way that I can
> access them from the initforms of the class's other slots?

I thing you want to use initforms for what they are not meant to be
used for.

> 3. Copying by value:
> 
> How can I copy an object field by field,

You do just that.

> (by value, not by reference), as with copy-structure? Do I need to
> copy each field explicitly, or is there some kind of generic "clone"
> function? (If so, I couldn't find it in the Hyperspec).

Read about this issue here: http://world.std.com/~pitman/PS/EQUAL.html

-- 
Janis Dzerins

  If million people say a stupid thing it's still a stupid thing.
From: John Flynn
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <PAIJ6.2666$ZJ.99636@ozemail.com.au>
"Janis Dzerins" <·····@latnet.lv> wrote in message
···················@asaka.latnet.lv...

[...]

> It will help you to forget for a while what you're accustomed to.

That shouldn't be too difficult. I'm not an expert in any language, nor am I
an expert programmer. I'm a bit of a wanderer looking to settle down into my
favourite two or three languages in order to become a more skilled
practitioner. So I don't have all that much knowledge to forget ...;-)

You're right, in that not much of what I know is helping me with CLOS. (I
don't mean to imply that's a problem, BTW. I'm intrigued by what I've seen
so far, and I'm pleased that the differences go much deeper than syntax).

I find CLOS (and Lisp in general) daunting and fascinating in equal
measures, and for the same reasons. It seems so versatile that a great deal
of skill and good taste will be necessary to use it effectively. And I
suspect (nay, fear!) that only one of these can be cultivated ;-)
From: Kent M Pitman
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <sfwlmo8zh42.fsf@world.std.com>
"John Flynn" <··········@yahoo.com.au> writes:

> I find CLOS (and Lisp in general) daunting and fascinating in equal
> measures, and for the same reasons. It seems so versatile that a great deal
> of skill and good taste will be necessary to use it effectively. And I
> suspect (nay, fear!) that only one of these can be cultivated ;-)

Don't be silly.  Perhaps the most surprising thing of all is that our
community values the idea of making concepts and power accessible and
understandable, even to non-wizards/gurus.  Rather than layer trivia on
obscurity, we have worked over decades to make the language allow you
to the ability to say obvious things in obvious ways, something I think
a lot of other languages have not always focused on as a priority.
Where you feel something is hard to understand or hard to use or requires
more skill than you have to offer, think of that as our failing as a 
community and not yours as a novice.
From: ········@hex.net
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <YLJJ6.8110$oa2.159184@news6.giganews.com>
Kent M Pitman <······@world.std.com> writes:
> "John Flynn" <··········@yahoo.com.au> writes:

>> I find CLOS (and Lisp in general) daunting and fascinating in equal
>> measures, and for the same reasons. It seems so versatile that a
>> great deal of skill and good taste will be necessary to use it
>> effectively. And I suspect (nay, fear!) that only one of these can
>> be cultivated ;-)

> Don't be silly.  Perhaps the most surprising thing of all is that
> our community values the idea of making concepts and power
> accessible and understandable, even to non-wizards/gurus.  Rather
> than layer trivia on obscurity, we have worked over decades to make
> the language allow you to the ability to say obvious things in
> obvious ways, something I think a lot of other languages have not
> always focused on as a priority.  Where you feel something is hard
> to understand or hard to use or requires more skill than you have to
> offer, think of that as our failing as a community and not yours as
> a novice.

Flip side: If something seems hard to understand or use, it's always
possible that this indicates that this abstraction truly is something
complex requiring considerable thought.

For instance, readtables seem to me to be fairly difficult to use.

On the one hand, there may be the problem that there aren't enough
good "HOWTOs" on the subject.  And there are bits of readtable setup
that appear more more painful than I'd think they need to be.

On the other hand, what readtables are trying to accomplish is fairly
abtruse, so it does not surprise me that it takes quite a lot of
thinking to make them useful.
-- 
(concatenate 'string "cbbrowne" ·@ntlug.org")
http://www.ntlug.org/~cbbrowne/resume.html
"Like I've always  said, if you don't have anything  nice to say, come
sit by me." -- Steel Magnolias
From: Kent M Pitman
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <sfwg0eg5wed.fsf@world.std.com>
········@hex.net writes:

> Flip side: If something seems hard to understand or use, it's always
> possible that this indicates that this abstraction truly is something
> complex requiring considerable thought.
> 
> For instance, readtables seem to me to be fairly difficult to use.

Well, certainly. I don't know about readtables--I'll have to think on 
that, since I think they're about as dead simple as anything comes--but
in general, I'm a big fan of mapping complexity one-on-one with the
real world, so that when you program and something is hard, you can either
simplify it by appealing to what you know about how you'd simplify your
world model, or you learn something about how much more complex the world 
is than you think it is. 

> On the one hand, there may be the problem that there aren't enough
> good "HOWTOs" on the subject.  And there are bits of readtable setup
> that appear more more painful than I'd think they need to be.

For future reference in design, I'd be curious to know what you find overly
complex.

> On the other hand, what readtables are trying to accomplish is fairly
> abtruse, so it does not surprise me that it takes quite a lot of
> thinking to make them useful.

I bet the actual difference is what your world model is coming into
it.  There's probably some difference between your presupposition of
what it is or should be trying to do that is making it look harder for
you than for me.  To me, the model of what they support is completely
straightforward--they aren't always useful for certain tasks they
aren't designed for, but they are very easy and useful for the tasks
they are designed for.  Anyway, I'll be really interested if you have
the time to explain how they were or seemed complicated or confusing.

In my experience, it's tough to get this sort of data.  People come in
with intuitions about what they expect and those intuitions are quickly
beaten down by the reality of what they get.  Intuition, to me as a 
professional who specializes in design is valuable as experience/knowledge
is to a newcomer.  To the extent possible, I'd like to cater to intuitions
rather than beat them down.  But they are fragile and often evaporate before
they can be studied, because often it takes more sophisticated language to
be able to discuss them, and by the time you have that language, you've
lost the initial impression.  I often say "mine experts for wisdom and
novices for intuitions".  Everyone's got something to contribute.
From: John Flynn
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <LKKJ6.2706$ZJ.102040@ozemail.com.au>
"Kent M Pitman" <······@world.std.com> wrote in message
····················@world.std.com...
>
> Don't be silly.  Perhaps the most surprising thing of all is that our
> community values the idea of making concepts and power accessible and
> understandable, even to non-wizards/gurus.  Rather than layer trivia on
> obscurity, we have worked over decades to make the language allow you
> to the ability to say obvious things in obvious ways [...]

Yeah ... I've already had a small taste of this. I wrote a simple logic game
last night to practice the basic use of lists, structures and functions.
Enjoyed every minute of it.

 > Where you feel something is hard to understand or hard to use or requires
> more skill than you have to offer, think of that as our failing as a
> community and not yours as a novice.

Thanks for the encouragement. I'll feel justified in this attitude when I've
paid my dues and learned more of the basics.
From: Tim Bradshaw
Subject: Re: Beginner's CLOS questions
Date: 
Message-ID: <ey3pudku5si.fsf@cley.com>
* John Flynn wrote:

> How can I copy an object field by field, (by value, not by
> reference), as with copy-structure? Do I need to copy each field
> explicitly, or is there some kind of generic "clone" function? (If
> so, I couldn't find it in the Hyperspec).

Kent answered the other stuff and pointed you to his excellent
equality paper, but you might want to look at my `one step beyond'
paper which is mostly about copying.  It's at
http://www.cley.com/articles/one-step-beyond.pdf.  (Please ignore the
rest of www.cley.com which is hugely out of date, we're going to
update it when we have time - this century I expect).

--tim