From: Christophe R. <cs...@ca...> - 2002-12-29 00:14:55
Attachments:
foo.diff
|
On Sat, Dec 28, 2002 at 10:25:04PM +0000, Christophe Rhodes wrote: > On Sat, Dec 28, 2002 at 12:52:50PM -0800, William Harold Newman wrote: > > new BUGS entry re. (I assume) 0.7.10.31 ctor.lisp stuff > > > > + In sbcl-0.7.10.33 (but not ca. 0.7.10.29), > > + (defclass foo54 () ()) > > + (reinitialize-instance (make-instance 'foo54) :dummy 0) > > + does not signal an error. ANSI's definition of REINITIALIZE-INSTANCE > > OK -- I'm on it (though Gerd, if you're playing along at home, you're > welcome to fix it for me -- or indeed anyone else... :-) I believe the attached fixes the bug. This area is probably ripe for optimization, though -- it looks slow and clunky, with calls to COMPUTE-APPLICABLE-METHODS and all -- but it's unlikely, I suspect, that optimizations will come along in the next couple of days, so this might have to do for now. The attached also fixes a bug Dan passed on to me at the SBCL Developers' (Southern England group) luncheon: (adjust-array (make-array 4) 4 :initial-contents "test") should return #(#\t #\e #\s #\t), not signal a type-error. Cheers, Christophe -- http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757 (set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b))) (defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge) |
From: Christophe R. <cs...@ca...> - 2002-12-29 14:39:54
|
On Sun, Dec 29, 2002 at 01:52:44PM +0000, Christophe Rhodes wrote: > On Sun, Dec 29, 2002 at 07:27:46AM +0100, Gerd Moellmann wrote: > > Couldn't sleep this night, so here it is, with memoization. Note that > > the ctor.lisp stuff is for what I have in my tree, which might be > > different from what is in SBCL. Please holler if you want my version. > > The other question is whether one could compute directly at Oh yes, one more other question. > + (labels ((reset (class &optional ri-cache-p (ctorsp t)) > + (when ctorsp > + (dolist (ctor (plist-value class 'ctors)) > + (install-initial-constructor ctor))) > + (when ri-cache-p > + (setf (plist-value class 'ri-initargs) ())) > + (dolist (subclass (class-direct-subclasses class)) > + (reset subclass ri-cache-p ctorsp)))) That recursion over subclasses currently happens unconditionally -- but it didn't happen before; should it be conditional on RI-CACHE-P, too? Cheers, Christophe -- http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757 (set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b))) (defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge) |
From: <ger...@t-...> - 2002-12-29 16:21:36
|
Christophe Rhodes <cs...@ca...> writes: > > + (labels ((reset (class &optional ri-cache-p (ctorsp t)) > > + (when ctorsp > > + (dolist (ctor (plist-value class 'ctors)) > > + (install-initial-constructor ctor))) > > + (when ri-cache-p > > + (setf (plist-value class 'ri-initargs) ())) > > + (dolist (subclass (class-direct-subclasses class)) > > + (reset subclass ri-cache-p ctorsp)))) > > That recursion over subclasses currently happens unconditionally -- but > it didn't happen before; should it be conditional on RI-CACHE-P, too? Oh, I forgot, the recursion is an unrelated bug fix and should happen unconditionally: * A bug in the optimized MAKE-INSTANCE implementation has been fixed, exemplified by this code (defclass s1 () ()) (defclass s2 (s1) ()) (defun f () (make-instance 's2)) (compile 'f) (f) (defmethod initialize-instance :before ((x s1) &rest args) (declare (ignore args)) (print "before")) (f) ==> before-method not being called |
From: Christophe R. <cs...@ca...> - 2002-12-29 18:44:47
|
On Sun, Dec 29, 2002 at 07:30:16PM +0100, Gerd Moellmann wrote: > Christophe Rhodes <cs...@ca...> writes: > > > arguments. The incidental point that my format string was > > completely wrong is, I hope, mitigated by the following one which > > works (tested, this time!) in: > > Yes, thanks, I found that too. (Strangely, I found myself first > looking at what the code does, then checking what CLHS says :). I confess to a certain amount of trial-and-error here, too. I think I'm getting better at it, but it's not yet perfect. > > debugger invoked on condition of type INITARG-ERROR: > > Invalid initialization arguments: > > :AA, :ZXMCKMJGY, :XZMCHGT, :QUUX, :BAZ, :BAR, :ADKRJ6GB, :ALSKJFY, > > :ALSKDJY, :ASLKDUTY, :ASDLKFH > > in call for class #<STANDARD-CLASS FOO>. > > Did you test with something short for the keys? I found I had to > insert 2 spaces. * (defclass foo () ()) #<STANDARD-CLASS FOO> * (make-instance 'foo :bar 3) debugger invoked on condition of type SB-PCL::INITARG-ERROR: Invalid initialization argument: :BAR in call for class #<SB-PCL::STANDARD-CLASS FOO>. There may be confusion over the pretty printer indentation, in that at least SBCL has a bug with respect to the prompt (BUG 64); that said, I get the above form consistently, so I dunno -- is that what you meant? Cheers, Christophe -- http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757 (set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b))) (defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge) |
From: <ger...@t-...> - 2002-12-29 20:05:11
|
Christophe Rhodes <cs...@ca...> writes: > * (defclass foo () ()) > > #<STANDARD-CLASS FOO> > * (make-instance 'foo :bar 3) > debugger invoked on condition of type SB-PCL::INITARG-ERROR: > Invalid initialization argument: > :BAR > in call for class #<SB-PCL::STANDARD-CLASS FOO>. > > There may be confusion over the pretty printer indentation, in that at > least SBCL has a bug with respect to the prompt (BUG 64); that said, I > get the above form consistently, so I dunno -- is that what you meant? Yes. That gave me "argument::BARin" here. Sigh, I shouldn't be playing with Intercal^Wformat. |
From: <ger...@t-...> - 2002-12-29 06:29:37
|
Christophe Rhodes <cs...@ca...> writes: > I believe the attached fixes the bug. This area is probably ripe for > optimization, though -- it looks slow and clunky, with calls to > COMPUTE-APPLICABLE-METHODS and all -- but it's unlikely, I suspect, that > optimizations will come along in the next couple of days, so this might > have to do for now. Couldn't sleep this night, so here it is, with memoization. Note that the ctor.lisp stuff is for what I have in my tree, which might be different from what is in SBCL. Please holler if you want my version. ;;; In init.lisp (defmethod reinitialize-instance ((instance slot-object) &rest initargs) (check-ri-initargs instance initargs) (apply #'shared-initialize instance nil initargs) instance) ;;; Collect and return invalid keys from these functions. (defun check-initargs-2-plist (initargs class legal &optional (error-p t)) (let ((invalid-keys ())) (unless (getf initargs :allow-other-keys) (doplist (key val) initargs (unless (memq key legal) (push key invalid-keys))) (when (and invalid-keys error-p) (simple-program-error "Invalid initialization argument~P~{ ~S~} for class ~S" (length invalid-keys) invalid-keys (class-name class)))) invalid-keys)) (defun check-initargs-2-list (initkeys class legal &optional (error-p t)) (let ((invalid-keys ())) (unless (memq :allow-other-keys initkeys) (dolist (key initkeys) (unless (memq key legal) (push key invalid-keys))) (when (and invalid-keys error-p) (simple-program-error "Invalid initialization argument~P~{ ~S~} for class ~S" (length invalid-keys) invalid-keys (class-name class)))) invalid-keys)) ;;; in ctor.lisp (defun update-ctors (reason &key class name generic-function method) (labels ((reset (class &optional ri-cache-p (ctors-p t)) (when ctors-p (dolist (ctor (plist-value class 'ctors)) (install-initial-constructor ctor))) (when ri-cache-p (setf (plist-value class 'ri-initargs) ())) (dolist (subclass (class-direct-subclasses class)) (reset subclass ri-cache-p ctors-p)))) (ecase reason ;; ;; CLASS must have been specified. (finalize-inheritance (reset class t)) ;; ;; NAME must have been specified. (setf-find-class (loop for ctor in *all-ctors* when (eq (ctor-class-name ctor) name) do (when (ctor-class ctor) (reset (ctor-class ctor))) (loop-finish))) ;; ;; GENERIC-FUNCTION and METHOD must have been specified. ((add-method remove-method) (flet ((class-of-1st-method-param (method) (type-class (first (method-specializers method))))) (case (generic-function-name generic-function) ((make-instance allocate-instance initialize-instance shared-initialize) (reset (class-of-1st-method-param method) t t)) ((reinitialize-instance) (reset (class-of-1st-method-param method) t nil)))))))) (defun check-ri-initargs (instance initargs) (let* ((class (class-of instance)) (keys (plist-keys initargs)) (cached (assoc keys (plist-value class 'ri-initargs) :test #'equal)) (invalid-keys (if (consp cached) (cdr cached) (let ((invalid (check-initargs-1 class initargs (list (list* 'reinitialize-instance instance initargs) (list* 'shared-initialize instance nil initargs)) t nil))) (setf (plist-value class 'ri-initargs) (acons keys invalid cached)) invalid)))) (when invalid-keys (simple-program-error "Invalid initialization argument~P ~{~s ~:_~}for class ~S" (length invalid-keys) invalid-keys class)))) |
From: <ger...@t-...> - 2002-12-29 10:10:17
|
Gerd Moellmann <ger...@t-...> writes: > Christophe Rhodes <cs...@ca...> writes: > > > I believe the attached fixes the bug. This area is probably ripe for > > optimization, though -- it looks slow and clunky, with calls to > > COMPUTE-APPLICABLE-METHODS and all -- but it's unlikely, I suspect, that > > optimizations will come along in the next couple of days, so this might > > have to do for now. Forgot to mention one change in ctor.lisp: In CONSTRUCTOR-FUNCTION-FORM, where CHECK-INITARGS-1 is called, make that (null (check-initargs-1 class (plist-keys (ctor-initargs ctor)) (append ii-methods si-methods) nil nil)) because of the change in CHECK-INITARGS-1. |
From: Christophe R. <cs...@ca...> - 2002-12-29 13:54:31
Attachments:
foo.diff
|
On Sun, Dec 29, 2002 at 07:27:46AM +0100, Gerd Moellmann wrote: > Christophe Rhodes <cs...@ca...> writes: > > > I believe the attached fixes the bug. This area is probably ripe for > > optimization, though -- it looks slow and clunky, with calls to > > COMPUTE-APPLICABLE-METHODS and all -- but it's unlikely, I suspect, that > > optimizations will come along in the next couple of days, so this might > > have to do for now. > > Couldn't sleep this night, so here it is, with memoization. Note that > the ctor.lisp stuff is for what I have in my tree, which might be > different from what is in SBCL. Please holler if you want my version. Thanks. This (with your other mail) makes my current diff the attached. I think I'm getting better at the punctuation soup of error message format strings, but please check my version... one other question is on the choice of an association list for the memoization data structure -- I believe Stig Sandoe measured (I don't know with what benchmark) that the break-even point in speed was approximately 3 entries (comparing alists and hash tables). The other question is whether one could compute directly at add-method/remove-method time the updated list of legal initargs, rather than memoizing the result at reinitialize-instance call-time (and, indeed, whether that would buy us anything). I'm not enamoured of the CHECK-INITARGS-1 interface, now that I've spent some time with it -- assuming this patch is OK for 0.7.11, I would hope to be able to refactor the interface early in 0.7.11.x. Many thanks, Christophe -- http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757 (set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b))) (defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge) |
From: <ger...@t-...> - 2002-12-29 16:18:51
|
Christophe Rhodes <cs...@ca...> writes: > I think I'm getting better at the punctuation soup of error message > format strings, but please check my version... Ah, very nice. I'll steal that :). > one other question is on the choice of an association list for the > memoization data structure -- I believe Stig Sandoe measured (I > don't know with what benchmark) that the break-even point in speed > was approximately 3 entries (comparing alists and hash tables). ISTR something like 15, but that may be data from decades ago. I've used an alist because I felt the lookup time doesn't matter much compared to generic function dispatch and esp. what SHARED-INITIALIZE does. > The other question is whether one could compute directly at > add-method/remove-method time the updated list of legal initargs, rather > than memoizing the result at reinitialize-instance call-time (and, > indeed, whether that would buy us anything). Hard to tell if it's worth doing. Out of the top of my head, I don't even remember a real program doing REINITIALIZE-INSTANCE. |
From: <ger...@t-...> - 2002-12-29 17:03:31
|
Gerd Moellmann <ger...@t-...> writes: > Christophe Rhodes <cs...@ca...> writes: > > > I think I'm getting better at the punctuation soup of error message > > format strings, but please check my version... > > Ah, very nice. I'll steal that :). I would have liked to steal that, but the format string doesn't seem to work in current CMUCL or SBCL 0.7.10.22: (format nil "~@<~{ ~S~^,~}~@:> ~S" '(1 2 3) 4) => error no more arguments in SBCL, CMUCL => "1, 2, 3 4" in ACL, CLisp |
From: Christophe R. <cs...@ca...> - 2002-12-29 17:23:55
|
On Sun, Dec 29, 2002 at 06:01:40PM +0100, Gerd Moellmann wrote: > Gerd Moellmann <ger...@t-...> writes: > > > Christophe Rhodes <cs...@ca...> writes: > > > > > I think I'm getting better at the punctuation soup of error message > > > format strings, but please check my version... > > > > Ah, very nice. I'll steal that :). > > I would have liked to steal that, but the format string doesn't seem > to work in current CMUCL or SBCL 0.7.10.22: > > (format nil "~@<~{ ~S~^,~}~@:> ~S" '(1 2 3) 4) > => error no more arguments in SBCL, CMUCL > => "1, 2, 3 4" in ACL, CLisp If the at-sign modifier is used with ~<...~:>, the entire remaining argument list is passed to the directive as its argument. All of the remaining arguments are always consumed by ~@<...~:>, even if they are not all used by the format string nested in the directive. In the above case, the format string receives the argument ((1 2 3) 4), and applies the internal bit -- "~{ ~S~^,~}" -- to each element in turn. OK. Thus, the difference between the implementations is expained by the difference in their handling of ~{ ~} with non-list arguments. The incidental point that my format string was completely wrong is, I hope, mitigated by the following one which works (tested, this time!) in: (define-condition initarg-error (program-error) ((class :reader initarg-error-class :initarg :class) (initargs :reader initarg-error-initargs :initarg :initargs)) (:report (lambda (condition stream) (format stream "~@<Invalid initialization argument~P:~2I~_~ ~<~{~S~^, ~}~@:>~I~_in call for class ~S.~:>" (length (initarg-error-initargs condition)) (list (initarg-error-initargs condition)) (initarg-error-class condition))))) which prints output of the form debugger invoked on condition of type INITARG-ERROR: Invalid initialization arguments: :AA, :ZXMCKMJGY, :XZMCHGT, :QUUX, :BAZ, :BAR, :ADKRJ6GB, :ALSKJFY, :ALSKDJY, :ASLKDUTY, :ASDLKFH in call for class #<STANDARD-CLASS FOO>. Cheers, Christophe -- http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757 (set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b))) (defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge) |
From: <ger...@t-...> - 2002-12-29 18:32:06
|
Christophe Rhodes <cs...@ca...> writes: > If the at-sign modifier is used with ~<...~:>, the entire remaining > argument list is passed to the directive as its argument. All of the > remaining arguments are always consumed by ~@<...~:>, even if they are > not all used by the format string nested in the directive. > > In the above case, the format string receives the argument ((1 2 3) 4), and > applies the internal bit -- "~{ ~S~^,~}" -- to each element in turn. OK. > Thus, the difference between the implementations is expained by the difference > in their handling of ~{ ~} with non-list arguments. The incidental point that > my format string was completely wrong is, I hope, mitigated by the following > one which works (tested, this time!) in: Yes, thanks, I found that too. (Strangely, I found myself first looking at what the code does, then checking what CLHS says :). [...] > debugger invoked on condition of type INITARG-ERROR: > Invalid initialization arguments: > :AA, :ZXMCKMJGY, :XZMCHGT, :QUUX, :BAZ, :BAR, :ADKRJ6GB, :ALSKJFY, > :ALSKDJY, :ASLKDUTY, :ASDLKFH > in call for class #<STANDARD-CLASS FOO>. Did you test with something short for the keys? I found I had to insert 2 spaces. |
From: <ger...@t-...> - 2002-12-29 17:28:10
|
Gerd Moellmann <ger...@t-...> writes: > I would have liked to steal that, but the format string doesn't seem > to work in current CMUCL or SBCL 0.7.10.22: > > (format nil "~@<~{ ~S~^,~}~@:> ~S" '(1 2 3) 4) > => error no more arguments in SBCL, CMUCL > => "1, 2, 3 4" in ACL, CLisp Maybe CMUCL/SBCL are even right. CLHS, 22.3.5.2 Tilde Less-Than-Sign: Logical Block If the at-sign modifier is used with ~<...~:>, the entire remaining argument list is passed to the directive as its argument. and (format nil "~<~{ ~S~^,~}~@:> ~S" '((1 2 3)) 4) => " 1, 2, 3 4" |
From: Pierre R. M. <pm...@pm...> - 2002-12-29 22:50:52
|
Am Sonntag, 29.12.02 um 17:17 Uhr schrieb Gerd Moellmann: > Hard to tell if it's worth doing. Out of the top of my head, I don't > even remember a real program doing REINITIALIZE-INSTANCE. FWIW, reinitialize-instance is used in a somewhat common idiom of CLOS usage, where we want to dispatch on the objects itself, when computing the initargs used to initialize the object properly, e.g. (let* ((entity (make-instance class)) (initargs (compute-entity-initargs entity headers))) (apply #'reinitialize-instance entity intargs) entity) (defmethod compute-entity-initargs ((entity lazy-entity) headers) ...) ... This makes initialization work even for newly defined subclasses with new default-initargs or new initforms, etc. Other approaches either don't work for subclasses, because they eql-dispatch on the objects class prior to creation, or they don't work nicely with the initargs mechanism, because they directly modify the objects slots. Regs, Pierre. -- Pierre R. Mai <pm...@ac...> http://www.pmsf.de/pmai/ The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents. -- Nathaniel Borenstein |