From: Kenny Tilton
Subject: How can I hack 'make-instance?
Date: 
Message-ID: <37A747D9.EC48962C@liii.com>
I /think/ I have seen code do this, and it almost seems to work, but
having a very bizarre problem...


I want to code:

   (make-instance 'myClass :copying t)

...where :copying is not a slot or initarg of 'myClass. I want to detect
that in the 'initialize-instance to avoid some heavy lifting there:

(defmethod initialize-instance :after ((DX myClass) &rest iargs)
   ;
   ; watch for timing error between setting user during login and
   ; creating DX for same
   ;
  (if (cadr (member :copying iargs))
     (trc "DX being copied")
     (progn 
	;heavy lifting
       )

What is so bizarre? This works on some classes but not others (and no
one has a "copying" initarg)...on some I get the error ":copying is not
a valid :initarg...."...no pattern detectible.

1. Well, is this legal anyway? If not, anyone know of a way to interfere
with 'i-i behavior on an ad hoc basis like this?

2. If it is legal (it works a little--I see "DX being copied" in the
trace!), geez, how /do/ i do this? Do I destructively modify the
initargs list in a before method on i-i?! yeeha.

cheers,

ken tilton
clinisys
acl 5.0.1
allegrostore 1.3
nt 4.0

From: Vassil Nikolov
Subject: Re: How can I hack 'make-instance?
Date: 
Message-ID: <l03130301b3ccfac6fb4e@195.138.129.99>
Kenny Tilton wrote:                [1999-08-03 15:49 -0400]

  [...]
  > I want to code:
  > 
  >    (make-instance 'myClass :copying t)
  > 
  > ...where :copying is not a slot or initarg of 'myClass. I want to detect
  > that in the 'initialize-instance to avoid some heavy lifting there:
  > 
  > (defmethod initialize-instance :after ((DX myClass) &rest iargs)
  [...]
  > What is so bizarre? This works on some classes but not others (and no
  > one has a "copying" initarg)...on some I get the error ":copying is not
  > a valid :initarg...."...no pattern detectible.
  > 
  > 1. Well, is this legal anyway? If not, anyone know of a way to interfere
  > with 'i-i behavior on an ad hoc basis like this?
  > 
  > 2. If it is legal (it works a little--I see "DX being copied" in the
  > trace!), geez, how /do/ i do this? Do I destructively modify the
  > initargs list in a before method on i-i?! yeeha.

My quick & dirty answer is that the methods for some classes already
have &ALLOW-OTHER-KEYS and others don't.

So you should supply it where necessary.


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.





 Sent via Deja.com http://www.deja.com/
 Share what you know. Learn what you don't.
From: Pierre R. Mai
Subject: Re: How can I hack 'make-instance?
Date: 
Message-ID: <873dy0a9dm.fsf@orion.dent.isdn.cs.tu-berlin.de>
Vassil Nikolov <········@poboxes.com> writes:

> My quick & dirty answer is that the methods for some classes already
> have &ALLOW-OTHER-KEYS and others don't.
> 
> So you should supply it where necessary.

Which, as you state would be Q&D, since this eliminates all initarg
validation.  Better to declare copying as a keyword argument on his
method, as I mention in my other posting.  See sections 7.1.2 and
7.6.5 of the HyperSpec.

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Vassil Nikolov
Subject: Re: How can I hack 'make-instance?
Date: 
Message-ID: <l03130301b3cd8ac0422e@195.138.129.99>
Pierre R. Mai wrote:                [1999-08-03 22:37 +0200]

  > Vassil Nikolov <········@poboxes.com> writes:
  > 
  > > My quick & dirty answer is that the methods for some classes already
  > > have &ALLOW-OTHER-KEYS and others don't.
  > > 
  > > So you should supply it where necessary.
  > 
  > Which, as you state would be Q&D, since this eliminates all initarg
  > validation.  Better to declare copying as a keyword argument on his
  > method, as I mention in my other posting.  See sections 7.1.2 and
  > 7.6.5 of the HyperSpec.

Yes, indeed.  I was basically trying to give a brief hint why different
classes behaved differently.  My second sentence above should in
fact be: `So you should supply ``&KEY COPYING'' where necessary.'

Thanks for correcting me.


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.





 Sent via Deja.com http://www.deja.com/
 Share what you know. Learn what you don't.
From: Paul Rudin
Subject: Re: How can I hack 'make-instance?
Date: 
Message-ID: <wkaes6issw.fsf@scientia.com>
>>>>> "Vassil" == Vassil Nikolov <········@poboxes.com> writes:


 Vassil> My quick & dirty answer is that the methods for some classes
 Vassil> already have &ALLOW-OTHER-KEYS and others don't.

 Vassil> So you should supply it where necessary.


Trouble with &allow-other-keys is that none of your key words get
checked. Unless there's a good reason not to

  &rest rest &key copying 

is maybe better?






 Sent via Deja.com http://www.deja.com/
 Share what you know. Learn what you don't.
From: Kenny Tilton
Subject: Re: How can I hack 'make-instance?
Date: 
Message-ID: <37AAF242.7E4FCAAB@liii.com>
BTW, thanks to everyone for...

Paul Rudin inter alia wrote:
> 
>   &rest rest &key copying
> 

Kind of fun to be learning something so basic at what I /thought/ was a
late stage in my CL development. So /that's/ what &allow-other-keys is
for! :)

Ken Tilton
CliniSys
The Next Commercial Lisp Application Success Story
From: Pierre R. Mai
Subject: Re: How can I hack 'make-instance?
Date: 
Message-ID: <87672wa9kf.fsf@orion.dent.isdn.cs.tu-berlin.de>
Kenny Tilton <····@liii.com> writes:

> I want to code:
> 
>    (make-instance 'myClass :copying t)
> 
> ...where :copying is not a slot or initarg of 'myClass. I want to detect
> that in the 'initialize-instance to avoid some heavy lifting there:

See the HyperSpec, section 7.1.2 Declaring the Validity of
Initialization Arguments.  Summary: InitArgs are declared valid either 
through :initarg options on slots, or through the definition of
keyword arguments on the applicable methods for the intended purpose.
In your case this would be initialize-instance (see also 7.6.5 for
Keyword Arguments in Generic Functions and Methods).

So in your example, write

(defmethod initialize-instance :after ((DX myClass) &rest iargs &key copying) 
  (declare (ignore iargs))  ; If iargs are not used further
  (if copying
      (trc "DX being copied")
      (progn
        ;;heavy lifting
        )))

and things should work correctly...

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Phil Stubblefield
Subject: Re: How can I hack 'make-instance?
Date: 
Message-ID: <37A778E2.4EA7EE7F@rpal.rockwell.com>
Kenny Tilton wrote:
> 
> I /think/ I have seen code do this, and it almost seems to work, but
> having a very bizarre problem...
> 
> I want to code:
> 
>    (make-instance 'myClass :copying t)
> 
> ...where :copying is not a slot or initarg of 'myClass. I want to
> detect that in the 'initialize-instance to avoid some heavy lifting
> there:
> 
> (defmethod initialize-instance :after ((DX myClass) &rest iargs)
>    ;
>    ; watch for timing error between setting user during login and
>    ; creating DX for same
>    ;
>   (if (cadr (member :copying iargs))
>      (trc "DX being copied")
>      (progn
>         ;heavy lifting
>        )

I do this kind of thing occasionally.  The trick is to understand how
initialization arguments are declared as valid.  For details, see
Section 7.1.2, "Declaring the Validity of Initialization Arguments,"
of the CL HyperSpec at:

  http://www.harlequin.com/education/books/HyperSpec/Body/sec_7-1-2.html

Basically, you declare an initialization argument (like `:copying') to
be valid by (1) specifying it as an `:initarg' to some slot in a
class; or (2) specifying it as a keyword argument to one of the CLOS
methods relevant to the current context.  For customizing instance
creation, `initialize-instance' is one such method.  So just change
your definition to look something like this:

(defmethod initialize-instance :after ((DX myClass) &key copying)
  ;; ...
  (when copying
    (trc "DX being copied")
    ;; Heavy lifting...
    )
  ;; ...
  )

You don't even need `&allow-other-keys' because the generic function
itself already specifies it.

Another occasion where you might want to use this functionality is
when the value of a slot can be set both at initialization time and
later during the lifetime of the instance, *and* when setting the
value requires additional steps.  For example, consider the following
(untested) code:

(defclass foo ()
  ((name
    :accessor foo-name
    :initarg :name
    :type string))
  (:default-initargs :name "Anonymous"))

(defmethod initialize-instance :after ((foo foo) &key)
  (with-slots (name) foo
    (check-type name string)
    (invoke-callback ':name name)))

(defmethod (setf foo-name) :before (name (foo foo))
  (check-type name string))

(defmethod (setf foo-name) :after (name (foo foo))
  (invoke-callback ':name name))

Here, the code checks that the name is a string, then invokes a
hypothetical callback.  Unfortunately, the auxiliary code is
replicated in multiple places, which is, of course, a Bad Thing.
Fortunately, several simple changes can rectify the situation:

(defclass foo ()
  ((name
    :reader foo-name                            ;writer below
    :type string)))

(defmethod initialize-instance :after ((foo foo) &key name)
  (setf (foo-name foo) (or name "Anonymous")))

(defmethod (setf foo-name) (name (foo foo))
  (check-type name string)
  (setf (slot-value foo 'name) name)
  (invoke-callback ':name name))

Here, the class definition no longer concerns itself with initargs, the
initialization method just calls the slot writer, and the slot writer
incorporates the auxiliary code into its own body to avoid a bunch of
messy (IMHO) `:before' and `:after' methods.  Voila!  No more duplicated
code, and the behavior is the same regardless of when you supply a name.

Some might choose to use the `:accessor' keyword to `defclass' and
just use the `:before' and `:after' methods above, but I personally
prefer getting the code in one place.  As a system grows, and the
number of applicable methods grows along with it, it can be difficult
to understand what a particular method invocation does.  In my
experience, avoiding extraneous methods helps keep the intent clear.
YMMV.

> What is so bizarre? This works on some classes but not others (and
> no one has a "copying" initarg)...on some I get the error ":copying
> is not a valid :initarg...."...no pattern detectible.

As Vassil already pointed out, you probably have `&allow-other-keys'
and/or `:allow-other-keys t' in some places but not in others.


Phil Stubblefield
Rockwell Palo Alto Laboratory                               206/655-3204
http://www.rpal.rockwell.com/~phil                ····@rpal.rockwell.com