How to Fix a Newbie's Borked Lisp Image

The Problem

One of the issues that I would run into with Common Lisp was that sometimes I would get my image into an unusable state. The lisp way is incremental development, and one shouldn't need to restart their image very often, so I am told. Every now and then though, I'd fire up Emacs, Slime, and SBCL. I'd load up my files in the wrong order and blamo! My image was borked. I would get this error:

The function :USE is undefined.

I'd abort the compilation. A ton of errors, warnings, and style-warnings would fly by. I must have committed a grievous sin in the eyes of all that is holy in lisp because my code is marked yellow, orange and red everywhere!

The error comes from my package definition supposedly:

(defpackage :test-chain1
   (:use :cl :cffi :ode :drawstuff))

The very first line of code in my file; it's totally idiomatic code. I haven't even been given a chance to upset compiler with my code below. The weird thing is :use isn't even supposed to be interpreted as a function. It's a keyword for the macro defpackage to interpret. In an edit, compile, run language, I would just make sure that I loaded those packages first before I ran my code again, problem solved. So, I try that. I evaluate these expressions to supply the necessary packages:

> (require 'cffi)
> (require 'cl-ode)
> (require 'cl-drawstuff)

Good. They load all right, so I try reloading my code. But it still doesn't work. When I try to reload my code, I get the same error about the :use function not being defined. WTF? That's not very nice of this environment to screw me for one early mistake. Please, I repent, REPL. I've loaded the packages you need, what more do you want from me!?

The Bad Solution

There is a relatively easy work-around, and it only requires that I sacrifice my insistence on accepting the lisp way of development: I can just restart my image and load my files in the right order. But I'd merely be betraying myself by living in this new lisp world by pretending it's just like the old C world. It's like the saying, you can write FORTRAN in any language. Well, edit-compile-runners can eek out an existence in any REPL environment provided they get hold of the on/off switch. Props to Marco for sneakily not revealing the on/off switch in his video how-to for slime. Too bad I found it anyway! [Whispers:] in Slime's REPL hit comma, 'r', 'e', ... [Door swings open.] *BANG* Marco!? hi, I wasn't [perspires] no, of course, not. [Marco leaves.] Um, you'll have to find it yourselves.

The Bumbling

I ventured into #lisp on and asked about how I could fix this problem since I knew I was violating the lisp way. I was a little worried about this because the lisp community kind of has a bad reputation when it comes to dealing with newbies. However, nobody told me to RTFM or dismissed me out of hand. nikodemus from #lisp said, "Time to learn about packages." Awesome. Where can I learn about them? rottcodd pointed me toward this tutorial, which is titled, "The Complete Idiot's Guide to Common Lisp Packages." I didn't take the title as a snub since it actually seems like a good guide. The section on packages in Common Lisp the Language gave me some tools to poke around into Common Lisp's package system. Anyway, the guys on #lisp were cool and helpful.

I played around to see if my package was being loaded.

> (find-package "test-chain1")
> (find-package "TEST-CHAIN1") ;; ah, uppercase package name
> (find-package :test-chain1)  ;; also works with the symbol reference (good to know)

The Solution

I did have a package called TEST-CHAIN1 loaded. What if I delete it? So I ran:

> (delete-package (find-package :test-chain1))

I crossed my fingers and reloaded my code. Fantastic! It compiled without issue. All the yellow, orange, and red smears against my integrity vanished. So I've fixed my image, but is this really how lispers deal with dependencies? In a word, no. Here are a few solutions to the underlying issue of code dependencies. The reason I went to the trouble of writing this up is so that, hopefully, one could google "The function :USE is undefined" and come up with a useful link.

The Quick Fix

This fix is implementation dependent (I'm using SBCL), so it is something you'd only want to rely on with your own personal code. You'd never want to distribute it.

(require 'cffi)
(require 'cl-ode)
(require 'cl-drawstuff)
(defpackage :test-chain1
  (:use :cl :cffi :ode :drawstuff))

The Good, Right, True, and Proper Fix

The best thing to do is get familiar with ASDF. That's how lispers actually manage dependencies in their code. ASDF with asdf-install is like Perl's CPAN or ruby's gem. xach from #lisp has a great tutorial on setting up a small lisp project and how to use ASDF to do it. Once I have that setup, I could do something like this:

> (require 'test-chain1)

It would load up all the required packages first (provided I set them up right in my .asd file). then load up my source file. And, finally, I have one less way of screwing up my image.

category: lisp