[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Comments on new draft chapter 1 (dated May 13 20:53)
- To: common-lisp-object-system@sail.stanford.edu
- Subject: Comments on new draft chapter 1 (dated May 13 20:53)
- From: Richard Mlynarik <MLY@AI.AI.MIT.EDU>
- Date: Fri, 20 May 88 17:35 EDT
These comments come from someone who has been keeping an eye on the
cl-o-o-p mail, but hasn't been reading the specs regularly and closely.
I'm omitting remarks which would overlap those in
<380679.880518.MOON@AI.AI.MIT.EDU>
A general remark on all of the documents -- as a non-American and as
something of a pedant I feel my blood-pressure rising every time I
encounter ``congruent with'' or ``different than'' in the documents (as
opposed to ``congruent to'' and ``different from'' respectively.) Is
this really Standard American English?
Another general remark is that Chapter 1 and Chapter 2 do not stand very
well apart from Chapter 3 -- there are too many functions mentioned in
passing which are never defined in any further fashion (or even
mentioned again!) This certainly makes for rather hard reading and
comprehension.
1-22 2nd PP in `Intro to methods': The first and second sentences
seem to be too directly contradictory. I would change the first to
``A method object is not NECESSARILY a function an IN GENERAL cannot be
invoked as a function.''
1-25 To this reader, the statement in the 4th enumerated PP that ``The
checking of the validity of keyword names is done in the generic
function, not in each method'' seems inconsistent with the second PP on
1-26 ``If a method is passed a keyword argument is does not accept, an
error is signaled.'' Is the indent to draw some distinction between &key
args from DEFGENERIC and those which come from random DEFMETHODs? If
so, this should be made a lot clearer.
1-31 2nd PP. ``to the :method-combination option to defgeneric or TO
THE :METHOD-COMBINATION OPTION TO any of the other forms that specify
generic function options.'' The uppercase text seems redundant.
1-31 5th PP. I would replace this with ``The simple build-in method
combination types COULD HAVE BEEN defined...''
1-32 <foo>
1-33 Penultimate PP. I am probably just plain confused on this point,
but is it possible that ``and instances of the classes standard-method,
...'' should read just ``the classes standard-method, ...''? The
reference to standard-method in the following bulleted PP reinforces my
probably-mistaken belief.
1-39 3rd PP. I question the use of the word ``captured'' (which occurs
in other places in both Chapters 1 and 2.) ``Inherited'' seems more
straight-forward to me. This is probably just a personal preference.
1-39 Table. The last line would seem to imply that the defaulted
initlist must always be '(a 1 a 2 b 2), ruling out the `optimization'
(a 1 b 2). Is this the intent? It seems to unnecessarily constrain the
behaviour of default-initargs methods.
1-39 The section `Shared-Initialize' The introduction of this section at
this point seems very unmotivated. Nowhere above (except by implication
of the `--'-bulleted PPs on 1-37) is it made clear that
shared-initialize is an `underlying' method called by all the various
(re)initialization methods. Some small preamble at the beginning of
this section would make a first-time reading of the the spec somewhat
easier.
At this point I suppose I might as well express my misgivings about
the name `shared-initialize' -- it seems to imply to me something to do
with `shared' (ie class-allocated) slots or something like that. For
what it's worth, I'll state that the names `initialize-slots,'
`basic-initialize' and even `common-initialize' (or even
`initialize'!) appeal to me more than `shared-initialize.'
1-39 Last PP. I would write ``The second argument to shared-initialize
may be one of the following:''
1-40 First (bulleted) PP. What if the instance doesn't have a slot with
named by one of the elements of the list? Is it ``an error?'' Is
slot-missing called?
1-40 4th bulleted PP. It should be noted that ``This happens regardless
of whether or not the slot is specified by the second argument.'' or
something along those lines -- make it completely clear that this first
step in initialization depends only on the &key initarg, not on the
slot-name-specification arg. I'd also like to see a similar comment in
the Chapter 2 doc for shared-initialize.
1-41 `Definitions of make-instance and initialize-instance'
I think that it would make the manual a lot easier to read if similar
sample definitions were provided for the other initializations methods
(reinitialize-instance, update-instance-for-xxx, ...) I think that
moving this section of sample definitions forward in the manual (perhaps
before the `shared-initialize' section, perhaps even very early in
`Objection Creation and Initialization') would provide much better
understanding of what the various generic functions do.
This would also somewhat alleviate my above-mentioned problems with
the unmotivated appearance of `shared-initialize.'
When I started reading from `Object Creation and Initialization' I
encountered a whole slew of names of generic functions on which I would
define methods, but no real reason for why I should want to do so for
around 7 more pages.
I personally find it much easier to be presented with an overall
framework of code and then later `fill in the blanks' by reading what
the purpose of the various functions are than to wade though pages of
passing references to lots of functions before discovering how they fit
together and how they are supposed to be useful.
1-41 Definition of make-instance. Is nobody else bothered by the fact
that the use DEFAULT-INITARGS may be a consful operation in the presence
of :default-initargs? It would be very easy for the evaluation of
DEFAULT-INITARGS to consume more storage (to construct a merged initargs
list) than that of ALLOCATE-INSTANCE does in creation of the instance
itself!
My first reaction to this is to suggest a definition like:
(defmethod make-instance ((class standard-class) &rest initargs)
(apply #'with-defaulted-initargs
(lambda (&rest defaulted-initargs)
...initarg error-checking code...
(let ((instance (apply #'allocate-instance
class defaulted-initargs)))
(apply #'initialize-instance instance defaulted-initargs)
instance))
class initargs))
[where any implementation worth its salt would provide some way to
declare the dynamic extent of the INITARGS argument and the
LAMBDA-expression.]
Of course there are other ways to do this sort of thing.
I don't believe that the permissible optimizations mentioned are
sufficient to stop me worrying about this point.
So, has nobody else considered this issue, or does nobody else
consider it an issue?
1-41 Last PP. What ``certain optimizations are permitted.'' Nothing is
mentioned here or in the Chapter 2 description of initialize-instance to
explain what these might be, any how they might affect writers of
methods on initialize-instance or shared-initialize. The Chapter 2
description of shared-initialize explains this -- there should be some
xref.
1-42 Last PP. I found this hard to read. Suggestion:
``As a result of various optimizations, not all of the functions and
methods involved in initialization need necessarily be called on every
call to {\bf make-instance} and, if called, they may not receive exactly
the arguments that one would expect based on the sample implementation
above.''
The example of a permitted optimization is bogus, because
check-keyword-arguments is not a method, and so the user has no business
redefining it, and so user methods have no way of telling whether it has
already been called or not (since it is stated that it won't signal an
error.)
My feeling is that the vagueness in this section is very
unpleasant, and quite inconsistent with the general precision in the
rest of the document. I have some ideas on how to improve this, if
there is any interest in re-opening this issue and in listening to them.
1-43 6th PP. The aside ``This two-step process ...'' disrupts the
description of what the process is. Is should be moved below, after the
sentence ``... and other user-defined actions.''
1-44 6th PP, 1-46 last PP, 1-48 4th PP.
I find these incredibly disjointed. For starters, only half of the
contract of the ``system-supplied primary method'' is mentioned -- the
other half is to be found two paragraphs down -- in a different section!
Secondly, I don't think much would be lost be replacing each occurrence
of the intrusively-long
Initialization arguments are declared as valid by using the {\bf
:initarg} option to {\bf defclass} or by defining methods for {\bf
<method-name>} or for {\bf shared-initialize}. See the section
``Declaring the Validity of Initialization Arguments'' for more information.
with simply:
(See the section ``Declaring the Validity of Initialization Arguments''
for more information.)
Here's a suggested rewrite (I'd find code easier to read than this
turgid techno-English any day...):
There is a system-supplied primary method for {\bf
update-instance-for-redefined-class} whose parameter specializer for
its instance argument is the class {\bf standard-object}. This
method first checks the validity of initialization arguments and
signals an error if an initialization argument is supplied that is not
declared as valid. (See the section ``Declaring the Validity of
Initialization Arguments'' for more information.) Then it calls the
generic function {\bf shared-initialize} with arguments of the
instance, a list of names of the newly added slots, and the
initialization arguments it received.
The now-redundant second half of the descriptions of these methods (with
appear in the ``Customizing foo'' sections) could be replaced by just
Methods for {\bf shared-initialize} may be defined to customize class
redefinition. See the section ``Shared-Initialize'' for more
information.
Finally, just to be contentious (I'm not inviting replies):
* I'm still convinced (after two years (even after reading all the
archived mail on the subject)) that optionals should be defaulted in the
generic function rather than the methods.... Oh well.
* I think it is a real loss that there is no way of specifying an
`interface function' such as New Flavors has. The mess with the stupid
optional arg for DOCUMENTATION methods in chapter 2 is an example of
this.
* I'm aware of the problems they entail -- however I still find it a
pity that there is no provision for `private' methods and slots.
* I find the omission of defclass :constructors to be a significant
loss, based on past experience with implementing this sort of thing.
* I rely upon and heavily use New Flavors defun-in-method. I don't see
how I could get equivalent performance via the use of WITH-SLOTS (since
I don't believe (the equivalent of) usage of a mapping table will be done
outside of method bodies.)
* I think that the use of STANDARD method combination for the various
initialization methods is a mistake. It is too easy (for a ready
example, see the mistake Moon pointed out in <380731.880518.MOON@AI.AI.MIT.EDU>
about 2-15) to bash the useful system-defined method. It is not at all
clear to me that it is ever useful to do this deliberately -- the only
thing it could do (which could not be done by defining an `auxiliary'
method on it or on shared-initialize) is inhibit error-checking.
I hold that the `two-pass' method-combination used in Flavors for
initialize-instance is the right sort of thing: initialize-instance and
reinitialize-instance should use `progn-with-:after' method combination,
and update-instance-for-redefined-class and
update-instance-for-different-class should use `progn-with-:before'
method combination (I can't think of a use for :after methods on these
gf's.)
Besides, use of non-STANDARD method-combination would actually show
readers that all this method-combination hair is actually good for
anything!
* I find the `evalness' of define-method-combination very disturbing.
It seems to me that a full lisp compiler or evaluator will need to be
present in any world into are loaded methods on generic functions which
use user-defined method-combination. I would -very- much like to be
convinced that this isn't the case.
* IWBNI GET and (SETF GET) were made generic, though I suppose the same
sort of argument could be made for dozens of other CLtL functions.