Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Evolving a lisp image

I love the idea of image-based languages, and lately I've been toying with Common Lisp via sbcl. I've read in a few places about how through being able to save and load back an image of the virtual machine, you can evolve an application or set of apps running on that image.

I get how to load code into an image and get it running, slime makes this sort of thing very nice, but my question is this: How can I tell what functions are defined in an image? Let's say I want to make an update to a function days or months after it has been running and I can't remember the name. Is there any way to get to the code or even just the names of the functions defined in an the image?

Now, I do write the code out into source and load it in via the repl, so I have a copy there, but it seems like this would be an obvious feature.

like image 823
clintm Avatar asked Feb 18 '11 23:02

clintm


2 Answers

Common Lisp has the idea of packages. Packages are kind of a registry for symbols and are used as namespaces for symbols. You can ask Common Lisp for a list of all packages.

CL-USER 1 > (list-all-packages)
(#<The SQL-COMMON package, 0/4 internal, 28/32 external>
 #<The LOOP package, 245/256 internal, 3/4 external>
 #<The COMM package, 0/4 internal, 940/1024 external>
 #<The REG package, 41/64 internal, 0/4 external>
 ...)

Each packages stores the interned symbols in some data structure. You can ask Common Lisp which symbols are interned in a package.

CL-USER 2 > (loop for symbol being
                each external-symbol in (find-package "COMMON-LISP")
             collect symbol)
(MAKE-ARRAY INVOKE-DEBUGGER STRING-TRIM ...)

To make that easier, Common Lisp provides functions APROPOS and APROPOS-LIST.

CL-USER 3 > (apropos "MAKE-LOCK")
MP::INTERNAL-MAKE-LOCK (defined)
MP:MAKE-LOCK (defined)
WWW-UTILS:MAKE-LOCK (defined)
MAKE-LOCK
RESOURCES::MAKE-LOCK (defined)
MINIPROC:MAKE-LOCK (defined)

Functions, Classes, etc. use symbols as their identifier. You can also ask a symbol, which function it denotes.

CL-USER 4 > (symbol-function 'www-utils:make-lock)
#<Function WWW-UTILS:MAKE-LOCK 41E006A69C>

Sometimes a Common Lisp also records the definition of functions. Then the function FUNCTION-LAMBDA-EXPRESSION can be used to retrieve 'it'.

CL-USER 5 > (defun foo (a) (* (sin a) a))
FOO

CL-USER 6 > (pprint (function-lambda-expression 'foo))

(LAMBDA (A)
  (DECLARE (SYSTEM::SOURCE-LEVEL #<EQ Hash Table{0} 41403151C3>))
  (DECLARE (LAMBDA-NAME FOO))
  (* (SIN A) A))

But usually nowadays Common Lisp implementations don't use the recorded definitions, but record the locations of the source for each Lisp construct.

Most Common Lisp implementations can track the source locations in an implementation specific way.

The Common Lisp standard defines a function ED.

CL-USER 7 > (ed 'www-utils:make-lock)

This calls an editor (internal or external) and should open the source code for that function. To make that work, Common Lisp needs to keep track of the source location for each function. Next the editor needs to have access to that source. Sometimes the location recorded is an absolute path /Users/joswig/lisp/utils.lisp . If the editor wants to open that file, it should be accessible. But it is also possible to use logical pathnames like http:server;utils.lisp . This is then translated into a real physical pathname. This translation can later be configured. So it would be possible to move a Lisp to a different machine with different pathnames, configure the logical pathname HTTP and then the Lisp still finds all source code, even though it is on a different machine with a different file system structure. So, to make it work may need some configuration. But it is a very useful feature and it is widely used.

How the recording of source code and how the recording of source locations work is implementation dependent and is a feature of the respective Lisp in combination with its development environment. Better Lisp implementations have a lot of features in this area.

like image 133
Rainer Joswig Avatar answered Oct 22 '22 05:10

Rainer Joswig


You can also use do-symbols or do-external-symbols if you prefer:

example:

>> (do-external-symbols (s (find-package :foo-package)) (print s))

FOO-PACKAGE:XXX
FOO-PACKAGE:YYY
FOO-PACKAGE:ZZZ
NIL

Where XXX, YYY & ZZZ are all external symbols in the package :foo-package.

like image 5
Shaun Avatar answered Oct 22 '22 07:10

Shaun