Add means to recover method definitions from method objects
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
New
|
Undecided
|
Unassigned |
Bug Description
One can get the definition of ordinary functios using FUNCTION-
Add a means for obtaining the source for a method from the method object, and also a means of replacing and restoring a method object for a generic function.
It might be necessary to cheat a bit due to methods being defined in a lexical environment which may no longer be available, but that applies to the lambda expression from FUNCTION-
The use case for this is to do mutation testing on Common Lisp code. This would involve getting the definitions of functions and methods, mutating them, and seeing if the test suite kills the mutants.
description: | updated |
description: | updated |
You can somewhat already do this, but function- lambda- expression give you a form that isn't as simple as you'd like. e.g. after doing (declaim (optimize sb-c:store- source- form))
then you can recover method expressions thusly:
* (function- lambda- expression pcl::%method- function- fast-function mop:method- function (find-method #'foozelize nil (list 'string)))))
(sb-
(sb-
(LAMBDA (SB-PCL::.PV. SB-PCL: :.NEXT- METHOD- CALL. SELF) :.NEXT- METHOD- CALL.)
(DISABLE- PACKAGE- LOCKS SB-PCL: :PV-ENV- ENVIRONMENT) ) :PV-ENV- ENVIRONMENT SB-PCL::DEFAULT)) PCL::FAST- LEXICAL- METHOD- FUNCTIONS ((SELF) SB-PCL: :.NEXT- METHOD- CALL.
(SELF) NIL :CALL-NEXT-METHOD-P NIL
:SETQ- P NIL :PARAMETERS-SETQD NIL
:METHOD- CELL (#:METHOD-CELL)
:APPLYP NIL) PACKAGE- LOCKS SB-PCL: :%PARAMETER- BINDING- MODIFIED) )
(SYMBOL- MACROLET ((SB-PCL: :%PARAMETER- BINDING- MODIFIED (QUOTE))) PACKAGE- LOCKS SB-PCL: :%PARAMETER- BINDING- MODIFIED) )
(DECLARE (IGNORABLE SB-PCL::.PV. SB-PCL:
(DECLARE (SB-PCL::%PARAMETER SELF))
(DECLARE (TYPE STRING SELF))
(DECLARE (IGNORABLE SELF))
(SYMBOL-MACROLET ((SB-PCL:
(SB-
(DECLARE (SB-PCL::%CLASS SELF STRING))
(LOCALLY
(DECLARE (DISABLE-
(DECLARE (ENABLE-
(BLOCK FOOZELIZE `(FOOZELIZED ,SELF)))))))
which is a complicated lambda coming from the rather simple source form:
(defmethod foozelize ((self string)) `(foozelized ,self))
This is, strictly speaking, analogous to DEFUN in that additional constructs are wrapped around the forms which literally appeared in source. e.g. (defun zot (y) (list (foo y))) leads to lambda- expression #'zot) => (LAMBDA (Y) (BLOCK ZOT (LIST (FOO Y))))
(function-
So in theory the information is available and I'm not sure the system per se ought to offer a way to extract the original lambda verbatim.
A major reason for not doing exactly what this request asks is that you'd have to think about the implications of passing that information all the way down to the guts of CLOS and not breaking anything about metaobject protocol. Specifically I'd be wary of the defmethod macro passing a quoted version of its original body to the programmatic method creator functions.
In addition to the resulting code bloat (if enabled by default), you then have the usual problems of forms that themselves are not re-externalizable for whatever reason. (It happens, and of course the STORE-SOURCE-FORM declaration is subject to that same problem, but it handles it by silently not recording the source, which is possible only by relying on compiler internals)
If you can figure out how to reverse-engineer the above form into something prettier, such logic would be suitable as an addition to sb-introspect I think.