From: George Lee
Subject: (defmethod (&optional I-want-typed))
Date: 
Message-ID: <77e6hl$gnj@news.acns.nwu.edu>
I have been searching for a reason why there is no support in CLOS for 

(defmethod do-somthing (&rest arg1 arg2 ... argn))

where arg1.. argn is of type foo
and where the args are typechecked.

I problem is that I would really like optional typed arguments so that if 
someone typed in 

(do-something <a-foo> <a-foo> <a-foo>... ) then everything is ok
however
(do-something <a-foo> <a-foo> <a-lemon>... ) then there should be an type 
error.  I think that I overheard somewhere that this is a efficiency issue but 
in cases where this wouldn't be the case, is there a solution?

I know that syntactically
(defmethod ((a foo) (b bar) &key (c 3))...
3 is a default for c.  

I am currently trying to think of a way of maybe macroing or maybe a before 
method which would give me the ability of doing something like this...

(defmethod do-something (&rest (stuff 'type-foo))
(defmethod do-something (&key (stuff 'type-stuff) (foo 'type-foo))

but I can't really think of a way to do this.

thanks beforehand for any help
From: Kent M Pitman
Subject: Re: (defmethod (&optional I-want-typed))
Date: 
Message-ID: <sfwaezp3yn0.fsf@world.std.com>
·····@nwu.edu (George Lee) writes:

> I have been searching for a reason why there is no support in CLOS for 
> 
> (defmethod do-somthing (&rest arg1 arg2 ... argn))
> 
> where arg1.. argn is of type foo
> and where the args are typechecked.

DEFMETHOD as it is in CLOS has never really seemed to me to be about
typechecking.  That's just a side benefit.  CLOS arguments get types
because they are dispatched on.  I think if the language had seriously
intended that typechecking were the prime benefit, it would have
offered type specializers for all the arg positions just as you suggest.

You can get type checking trivially just by adding a call to check-type.
e.g.,

 (defmethod do-something ((x frob) &optional y)
   (check-type y (or null frob) "a FROB or NIL")
   ...)

It would be trivial also to write your own version of DEFMETHOD that
did this for you if you just had a syntax you wanted to use.  Coming
up with a good syntax is hairy because the existing syntax already
permits the specification of default values, supplied-p, and in the
case of keywords, specifying the keyword.

In case your problem is figuring out how to type check a rest list,
I have done the following in the few cases I've been ambitious enough
to care:

 (defmethod do-something (&rest things)
   (dolist (thing things)
     (check-type thing (integer 1) "a natural number"))
   ...)

Though this does have the problem that if the type is violated and
the user corrects it, it will assign THING and then THING's value
will not get put back into THINGS.  To be fully semantically correct
you probably want:

 ;I didn't test this.  Caveat emptor.
 (defmacro check-types (list-var element-type &rest type-desc)
   (let ((element-var (gensym (format nil "ELEMENT-OF-~A" list-var))))
     `(do ((,list-var ,list-var (cdr ,list-var)))
          ((null ,list-var))
        (let ((,element-var (car ,list-var)))
          (check-type ,element-var ,element-type ,@type-desc)
          (setf (car ,list-var) ,element-var)))))

 (defmethod do-something (&rest things)
   (check-types things (integer 1) "a natural number")
   ...)

> I problem is that I would really like optional typed arguments so that if 
> someone typed in 
> 
> (do-something <a-foo> <a-foo> <a-foo>... ) then everything is ok
> however
> (do-something <a-foo> <a-foo> <a-lemon>... ) then there should be an type 
> error.  I think that I overheard somewhere that this is a efficiency issue but 
> in cases where this wouldn't be the case, is there a solution?

The only efficiency issue I can see is that if you don't need to dispatch
off of all the data, you shouldn't check the type of things you don't
need to dispatch off of in order to do the dispatch.  but that doesn't mean
you shouldn't check the type for other reasons.  If it's a potential
problem, you have to check it at some point...
 
> I know that syntactically
> (defmethod ((a foo) (b bar) &key (c 3))...
> 3 is a default for c.  
> 
> I am currently trying to think of a way of maybe macroing or maybe a before 
> method which would give me the ability of doing something like this...
> 
> (defmethod do-something (&rest (stuff 'type-foo))
> (defmethod do-something (&key (stuff 'type-stuff) (foo 'type-foo))

Well, the problem is that defmethod already has a meaning for this.
You could (with macros and shadowing of DEFMETHOD with your own
variant) extend the syntax to say that 
 &key (var [val [supplied-p] [:type type]])
Oh, btw, I tend to use type and class quite messily in casual 
conversation, but I should note that though indeed a "type" (as
CLHS calls it) is appropriate here, a "class" is required in the
argument specializers for required args.  One can't dispatch
off of all types--only off of classes.  But one can type-check
on types....  (well, except those goofy ones for functions of
typed arguments.    but forget i mentioned those)
 
> but I can't really think of a way to do this.
> 
> thanks beforehand for any help

Not sure if this helped or just confused things more, but if you can
get something out of it, you're welcome.