|
I'm not sure what you're pointing at there. I'm aware of method combinations and method qualifiers—are you referring to being able to add a general :before/:after/:around on a single generic? If so, that's not what I mean; what I mean is vaguely similar but on the first-arg dispatch axis. Here's a toy Python example. Given: class KnowItAll(object):
def __getattr__(self, attr):
return lambda: "yes, I know how to " + attr
We then have: >>> k = KnowItAll()
>>> k.reveal()
'yes, I know how to reveal'
>>> k.transfigure()
'yes, I know how to transfigure'
>>> k.make_sandwiches()
'yes, I know how to make_sandwiches'
Ruby does this with method_missing instead, which is where I'm most used to it happening (and I think it's used a lot more in Ruby than in Python owing to the language-culture's higher tolerance for magic). Smalltalk used doesNotUnderstand, IIRC. One of the key secondary results of this is that you can do things like https://paste.ee/p/tUaRP, which is a toy “Tracer” class which intercepts, prints, and forwards method calls and attribute accesses (ignoring some edge cases).If we were in CLOS, and started with: ;;; widget.lisp
(defclass widget () ((radius :initarg :radius)))
(defmethod grow ((w widget)) (incf (slot-value w 'radius)))
What I would expect for the equivalent is that, given: ;;; tracer.lisp
(declaim (ftype (function (t) t) make-tracer))
(defun make-tracer (object) ...)
;; ... further code goes here ...
Somewhere else, we can do: ;;; fiddle-with-widgets.lisp
(let* ((w (make-instance 'widget :radius 3))
(w* (make-tracer w)))
;; ???
(grow w*))
Can you add code to tracer.lisp, without specific reference to anything from widget.lisp, such that this has the effect of (grow w) but prints what it's doing? Note also that my use of slot-value above is very deliberately a ‘raw’ access. I'm here completely ignoring the “make up entirely new methods on the fly as needed” part that method_missing also gets used for, which is even more impossible in CLOS given that it would require intercepting, what, all symbol lookups…In CLOS, the class doesn't ‘own’ the method, it provides a type for dispatching on, so there's no way to do “give me some control over every generic function so long as the first arg is of ‘my’ type”. Which is a reasonable model, but means you can't do the same thing. Indeed the flip side is that in the Smalltalk-like model, generics are not reified, and methods that are specializations of the ‘same’ thing have no ‘real’ identity to them, so you can't do a type-ignoring :around method for an ‘entire generic’. (Often there will be a superclass to attach to instead, but it's considered dangerous “monkey patching” to mess around with someone else's class hierarchy like that, and in the case of more abstract interfaces there's nothing.) Does that make sense? |