[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

check-keyword-arguments



I want to present one more alternative to the initargs checking
problem. This alternative was the result of a couple of hours'
discussion with Guy Steele tuesday night. There are two parts to
it. One is the real technical proposal, and the remainder is the
packaging for chapter 1.

We could introduce a new generic function called valid-keywords, which
takes an object; if it is something with keywords (like a generic
function, a method, or a function), valid-keywords returns two values: a
list of the explicitly named keywords and a boolean which states whether
&allow-other-keys had been specified in the definition.

Then we could write make-instance like this:

(defmethod make-instance ((class standard-class) &rest initargs)
  (setq initargs (default-initargs class initargs))
  (let* ((proto (class-prototype class))
         (methods 
           (union
	     (compute-applicable-methods #'allocate-instance `(,class))
	     (union
	       (compute-applicable-methods #'initialize-instance `(,proto nil))
	       (compute-applicable-methods #'shared-initialize `(,proto))))))
	(unless
	 (subsetp
	  (let ((keys '()))
	       (do ((plist initargs (cddr plist)))
		   ((null plist) keys)
		   (push (car plist) keys)))
	  (union 
	    (class-slot-initargs class)
	    (reduce #'union (mapcar #'valid-keywords methods))))
	(error ...)))
  (let ((instance (apply #'allocate-instance class initargs)))
    (apply #'initialize-instance instance initargs)
    instance))

Or something like this: the details of the code are not important
for chapters 1 and 2.

This is not a very simple piece of code to present in chapter 1. So
the proposal requires a sample of how to explain this:

\beginsubSection{Definitions of Make-Instance and Initialize-Instance}

The generic function {\bf make-instance} behaves as if it were defined as
follows, except that certain optimizations are permitted:

\screen!

(defmethod make-instance ((class standard-class) &rest initargs)
  (setq initargs (default-initargs class initargs))
  ...
  (let ((instance (apply #'allocate-instance class initargs)))
    (apply #'initialize-instance instance initargs)
    instance))

(defmethod make-instance ((class-name symbol) &rest initargs)
  (apply #'make-instance (find-class class-name) initargs))

\endscreen!

The elided code in the definition of {\bf make-instance} checks the
supplied initialization arguments to determine whether an initialization
argument was supplied that neither filled a slot nor supplied an argument
to an applicable method. This check could be implemented using the generic
functions {\bf class-prototype}, {\bf compute-applicable-methods}, {\bf
valid-keywords}, and {\bf class-slot-initargs}. See Chapter~3 for a
description of this initialization argument check.

The generic function {\bf initialize-instance} behaves as if it were
defined as follows, except that certain optimizations are permitted:

\screen!

(defmethod initialize-instance ((class standard-class) &rest initargs)
  (apply #'shared-initialize instance t initargs)))
 
\endscreen!

These procedures can be customized at either the Programmer Interface level,
the meta-object level, or both.  

Customizing at the Programmer Interface level includes using the {\bf
:initform}, {\bf :initarg}, and {\bf :default-initargs} options to
{\bf defclass}, as well as defining methods for {\bf make-instance}
and {\bf initialize-instance}.  It is also possible to define
methods for {\bf shared-initialize}, which would be invoked by the
generic functions {\bf reinitialize-instance}, {\bf
update-instance-for-redefined-class}, {\bf
update-instance-for-different-class}, and {\bf
initialize-instance}.  The meta-object level supports additional
customization by allowing methods to be defined on {\bf
make-instance}, {\bf default-initargs}, and {\bf
allocate-instance}.  Chapters~2 and~3 document each of these generic
functions and the system-supplied primary methods.

Implementations are permitted to make certain optimizations to {\bf
initialize-instance} and {\bf shared-initialize}.  The
description of {\bf shared-initialize} in Chapter~2 mentions the
possible optimizations.

Because of optimization, the check for valid initialization arguments
might not be implemented using the generic functions {\bf
class-prototype}, {\bf compute-applicable-methods}, {\bf valid-keywords},
and {\bf class-slot-initargs}. In addition, methods for the generic
function {\bf default-initargs}, and the system-supplied primary methods
for {\bf allocate-instance}, {\bf initialize-instance}, and {\bf
shared-initialize} may not be called on every call to {\bf make-instance}
or may not receive exactly the arguments that would be expected.

\endsubSection%{Definitions of MAKE-INSTANCE and Initialize-Instance}