From: William H. N. <wil...@ai...> - 2003-01-30 15:47:46
|
On Thu, Jan 30, 2003 at 02:14:33PM +0000, Christophe Rhodes wrote: > As Gerd Moellmann pointed out on cmucl-imp, > (defclass #:foo () ()) > is currently broken. And, as we've noted before, doing package > manipulations on packages that contain symbols naming classes is a > good way of getting code to break, because of all the horrible > interning of "~S constructor" or whatnot into *THE-PCL-PACKAGE*. > > Attached is a patch that solves the defclass issue, above. It does so > by introducing a generalization on function names: whereas before, > only symbols and (SETF symbol) names were legal, now added to these is > (SB-PCL::CLASS-PREDICATE symbol). Feel free to criticize this > decision of naming scheme -- this is likely to be a difficult area to > get right, even if I don't anticipate this particular generalization > being exposed to the user. > > Other possible uses for generalized function names include naming > internal functions (FLET FOO BAR) for > (defun bar () > (flet ((foo () ...)))); > (METHOD FOO :AROUND (T)) for > (defmethod foo :around (x) ...); > this might help in tracing, profiling and the like, and probably in > things I haven't thought of. > > Comments? Internally in PCL, I have wished for names in the (METHOD ...) style for some time. It certainly seems that they could make PCL implementation cleaner, so I was unsurprised to find Gerd shouting for them as well. And yes, FLET and LABELS compound names also look useful for the implementation of SBCL. I'm pretty sure this can be done acceptably cleanly as a private, internal implementation technique, and it looks like it's worth doing. It might even be worth adding a public extension allowing app program code to extend function names. E.g. DEFINE-FUNCTION-NAMESPACE could enable a new class of function names, where (define-function-namespace frob) causes names of the form (FROB ...) to be legal afterwards, and perhaps (define-function-namespace frob :syntax-checker (lambda (compound-name) (unless (and (= (length compound-name) 2) (symbolp (second compound-name))) (error "bad FROBber, must be (FROB SYMBOL)")))) causes an error to be signalled if someone tries to intern a compound name beginning with FROB which isn't of the form (FROB FOO). I am not volunteering at the moment to try to specify this carefully and determine how painful it would be to fit this in with everything else that ANSI specifies, but if it could be done cleanly, I might be receptive to sticking it into SBCL. An example of app-level code which might benefit from this is ;;; automating the idiom of *C*all with *LAM*bda, and my convention of ;;; having the implementing function name begin with "CLAM-" ;;; ;;; Note: The mnemonic justification for having BODY-ARGS precede ;;; PASSED-ARGS is that it resembles the convention used in DOLIST and ;;; DOTIMES (and used in the other iteration macros which I've ;;; modelled on DOLIST and DOTIMES). (export 'clam) (defmacro clam (stem body-args passed-args &body body) (declare (type string stem)) (declare (type list body-args passed-args)) (let ((bodyfnn (gensymicate "CLAM--" stem "--"))) `(flet ((,bodyfnn ,body-args ,@body)) (,(symbolicate "CLAM-" stem) #',bodyfnn ,@passed-args)))) where you can do things like (setf (fdefinition 'clam-on-keys-and-values) #'maphash) (clam "ON-KEYS-AND-VALUES" (k v) (hash-table) ...) or (defgeneric clam-with-locked (fn lockable) ...) and (defun clam-on-adjacent-things (fn thing) ...) and then (clam "WITH-LOCKED" () (element) ...) or (clam "ON-ADJACENT-THINGS" (adjacent-thing) (thing) (when (stale? adjacent-thing) (error "bad neighborhood")) (incf subtotal (property-of adjacent-thing)) (when (enemy? adjacent-thing) (vector-push-extend adjacent-thing enemy-adjacent-things))) instead of (clam-on-adjacent-things (lambda (adjacent-thing) (when (stale? adjacent-thing) (error "bad neighborhood")) (incf subtotal (property-of adjacent-thing)) (when (enemy? adjacent-thing) (vector-push-extend adjacent-thing enemy-adjacent-things))) thing) This CLAM stuff isn't anything deep, obviously, but then neither is SETF. And the implementation above, smashing the compound name into a single symbol, works acceptably well, but it would be tidier if one could do (define-function-namespace clam) and (defun (clam on-adjacent-things) (fn thing) ...) for the same sorts of reasons that SETF works better as (defun (setf foo) (...) ...) than it would if we were still doing (defun setf-foo (...) ...) It seems like this compound function name functionality is something that would naturally occur to any ANSI implementor to use internally. If I remember correctly, ACL at least already uses it. So, such an extension might in many cases simply be making public and portable functionality which already exists, which makes it sort of appealing to me. On the other hand, it must have occurred to Steele and the ANSI standardizers too, and they didn't do it, so maybe there's some downside which hasn't occurred to me... -- William Harold Newman <wil...@ai...> Furious activity is no substitute for understanding. -- H. H. Williams PGP key fingerprint 85 CE 1C BA 79 8D 51 8C B9 25 FB EE E0 C3 E5 7C |