What happens when you want to share the thing you built with somebody else? If I type a defun into a REPL, is there a good way to get source code back out again?
Because there's a problem I've run into several times when writing Lisp (I use SLIME): I decide to refactor some stuff, so I rewrite some stuff, maybe remove a function or two from the source as part of that. Things seem to be working fine. I save my .lisp files and then at some point end up restarting the Lisp process (often because McCLIM can be kind of flaky and lose its connection to the X server). When I go to load my code back in, I get errors, because oops I was actually still calling that deleted function somewhere -- it "worked" before because the old function was still hanging out in the image.
When I develop in a compiled language, I just accept that I'm going to be re-building the entire thing from scratch (equivalent to restarting the lisp process & re-loading the source files) every time I want to try a change; if I broke something, I'll find out the next time I run make/go build/whatever. When I'm developing in Lisp, and I'll freely accept that my Lisp dev flow probably isn't ideal, it's so easy to screw up but be unaware of it for hours if not days: I write some code, I'm happy, I close Emacs, then a week later I come back and try to load my package and it's just broken.
I could solve it for myself by just using images: the "deleted" function would persist in the image, and every time I started working again it would be there. But if I ever want to let somebody look at the code, hack on it, make changes, what's that look like?
> If I type a defun into a REPL, is there a good way to get source code back out again?
this used to be the normal way of programming in lisp repls (like in 01980) but maybe this is good enough
* (defun tri (n) (loop for i from 1 to n summing n))
TRI
* (describe 'tri)
COMMON-LISP-USER::TRI
[symbol]
TRI names a compiled function:
Lambda-list: (N)
Derived type: (FUNCTION (T) (VALUES NUMBER &OPTIONAL))
Source form:
(LAMBDA (N)
(BLOCK TRI
(LOOP FOR I FROM 1 TO N
SUMMING N)))
> When I go to load my code back in, I get errors, because oops I was actually still calling that deleted function somewhere -- it "worked" before because the old function was still hanging out in the image.
so a thing you can do in that case is to delete it from the image at the same time
well, you can't really delete it from the image, but you can remove the function binding of the symbol, and since normally in common lisp implementations function calls indirect through the symbol (which is why you can replace the definition with a newer one) deleting the function binding is enough
* (defun tri0 (n) (tri (1+ n)))
TRI0
* (tri0 4)
25
* (tri0 5)
36
* (fmakunbound 'tri)
TRI
* (tri0 5)
debugger invoked on a UNDEFINED-FUNCTION @52A00674 in thread
#<THREAD "main thread" RUNNING {1001348003}>:
The function COMMON-LISP-USER::TRI is undefined.
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [CONTINUE ] Retry calling TRI.
1: [USE-VALUE ] Call specified function.
2: [RETURN-VALUE ] Return specified values.
3: [RETURN-NOTHING] Return zero values.
4: [ABORT ] Exit debugger, returning to top level.
("undefined function" 6)
0]
as rainer pointed out, slime has a command for this (i barely use cl myself, you know much more than i do)
I work in a slightly different way by always saving my code in emacs and loading it fresh each session (though I have gone a couple of weeks with a live image/session on my laptop). I am fortunate that my 3D system [0] compiles and loads in a few seconds.
I also use the REPL for quick tests, and evaluate new code by writing it in emacs and compiling it one function at a time (C-c C-c).
Finally, I keep files of tutorial/demo/test cases which work a bit like a notebook, allowing me to quickly verify that existing 3D scenes still work.
Because there's a problem I've run into several times when writing Lisp (I use SLIME): I decide to refactor some stuff, so I rewrite some stuff, maybe remove a function or two from the source as part of that. Things seem to be working fine. I save my .lisp files and then at some point end up restarting the Lisp process (often because McCLIM can be kind of flaky and lose its connection to the X server). When I go to load my code back in, I get errors, because oops I was actually still calling that deleted function somewhere -- it "worked" before because the old function was still hanging out in the image.
When I develop in a compiled language, I just accept that I'm going to be re-building the entire thing from scratch (equivalent to restarting the lisp process & re-loading the source files) every time I want to try a change; if I broke something, I'll find out the next time I run make/go build/whatever. When I'm developing in Lisp, and I'll freely accept that my Lisp dev flow probably isn't ideal, it's so easy to screw up but be unaware of it for hours if not days: I write some code, I'm happy, I close Emacs, then a week later I come back and try to load my package and it's just broken.
I could solve it for myself by just using images: the "deleted" function would persist in the image, and every time I started working again it would be there. But if I ever want to let somebody look at the code, hack on it, make changes, what's that look like?