May 4, 2008
Function encapsulation in SBCL
The advice functionality allows the programmer to replace or encapsulate an existing function binding (akin to :AROUND methods in the CLOS). See Gary King’s “What is advice” for some useful links and explanations on this.
CLISP and SBCL, my favourite Common Lisp implementations, do not seem to supply this functionality. I haven’t checked whether CLISP has advice under its hood, but SBCL does, and it’s termed “Function encapsulation” there. Once you know how to do it, it’s surprisingly simple to use.
This is the definition of SB-INT:ENCAPSULATE in SBCL’s src/code/fdefinition.lisp:
;;; Replace the definition of NAME with a function that binds NAME's ;;; arguments to a variable named ARG-LIST, binds name's definition ;;; to a variable named BASIC-DEFINITION, and evaluates BODY in that ;;; context. TYPE is whatever you would like to associate with this ;;; encapsulation for identification in case you need multiple ;;; encapsulations of the same name. (defun encapsulate (name type body) (let ((fdefn (fdefinition-object name nil))) (unless (and fdefn (fdefn-fun fdefn)) (error 'undefined-function :name name)) ;; We must bind and close over INFO. Consider the case where we ;; encapsulate (the second) an encapsulated (the first) ;; definition, and later someone unencapsulates the encapsulated ;; (first) definition. We don't want our encapsulation (second) to ;; bind basic-definition to the encapsulated (first) definition ;; when it no longer exists. When unencapsulating, we make sure to ;; clobber the appropriate INFO structure to allow ;; basic-definition to be bound to the next definition instead of ;; an encapsulation that no longer exists. (let ((info (make-encapsulation-info type (fdefn-fun fdefn)))) (setf (fdefn-fun fdefn) (named-lambda encapsulation (&rest arg-list) (declare (special arg-list)) (let ((basic-definition (encapsulation-info-definition info))) (declare (special basic-definition)) (eval body)))))))
From this we can figure out that basic advice can be gotten from SBCL like this:
CL-USER(19): (defun gorm (x) (1+ x)) GORM CL-USER(20): (SB-INT:ENCAPSULATE 'gorm 'identity '(apply sb-int:basic-definition sb-int:arg-list)) #<closure (SB-C::&OPTIONAL-DISPATCH SB-IMPL::ENCAPSULATION) {ACE428D}> CL-USER(21): (gorm 10) 11 CL-USER(22): (SB-INT:ENCAPSULATE 'gorm 'add-five '(+ 5 (apply sb-int:basic-definition sb-int:arg-list))) #</closure><closure (SB-C::&OPTIONAL-DISPATCH SB-IMPL::ENCAPSULATION) {ACEE31D}> CL-USER(23): (gorm 10) 16 CL-USER(24): (SB-INT:ENCAPSULATE 'gorm 'add-seven '(+ 7 (apply sb-int:basic-definition sb-int:arg-list))) #</closure><closure (SB-C::&OPTIONAL-DISPATCH SB-IMPL::ENCAPSULATION) {ACF84ED}> CL-USER(25): (gorm) 23 </closure>
We have built a pretty onion, each layer of which calls the next inner layer via BASIC-DEFINITION (the analog to CALL-NEXT-METHOD). Let’s peel specific layers from it:
CL-USER(26): (SB-INT:UNENCAPSULATE 'gorm 'add-five) T CL-USER(27): (gorm 10) 18 CL-USER(28): (SB-INT:UNENCAPSULATE 'gorm 'add-seven) T CL-USER(29): (gorm 10) 11
Comments(2)
or function wrappers in cmucl
You may want to check this doc page for more info
http://common-lisp.net/project/cmucl/doc/cmu-user/extensions.html#toc82
regards
[...] public links >> sbcl Function encapsulation in SBCL Saved by sjrme on Wed 15-10-2008 Running SBCL on Windows Saved by Terrijlewis on Tue 14-10-2008 [...]