tags:

views:

56

answers:

1

I'm currently playing with lispbuilder-sdl on SBCL under Windows.

My source code is as follows:

(asdf:operate 'asdf:load-op :lispbuilder-sdl)
(asdf:operate 'asdf:load-op :lispbuilder-sdl-binaries)
(asdf:operate 'asdf:load-op :lispbuilder-sdl-examples)
(sdl-examples:squashed)

When I compile the file I get the error: package "SDL-EXAMPLES" not found.

If I remove the (sdl-examples:squashed) from the file it compiles ok. I can then type (sdl-examples:squashed) at the repl and the demo game starts fine.

Why is the sdl-examples package found from the repl but not when I compile the file?

+2  A: 

All of the compilation of that file happens before executing any of the load-ops. So when Lisp compiles the (sdl-examples:squashed) line, it hasn't run the load-op that defines your package.

You can get around this by not mentioning the sdl-examples package that requires the reader to locate its squashed symbol before the load-op is actually executed:

(funcall (symbol-function (intern (symbol-name '#:squashed)
                                  (find-package (symbol-name '#:sdl-examples)))))

The idea is to calculate the package from its symbolic name, lookup the symbol naming your function, and fetch the function it names - but this way requires that the package exist only when the code is run, not when it is first read. Then your four statements can all be compiled, executed in order, and by the time that last statement is executed, your load-ops will have created the package.


So here's a little more info about what's happening here:

  • Writing '#:some-name refers to a symbol that's not part of any package. So that way we can make a reference to a symbolic name without either (1) assuming its package exists or (2) mucking up some other package with the name.
  • Then '(symbol-name #:some-name) extracts the name of the symbol as a string. Why not just write "some-name"? You could, and it will usually work. But this way is a little more robust for the case of running a "modern-mode" case-sensitive Lisp.
  • The find-package maps a string name to Lisp's representation of a package. Remember, by the time you run this line, your package will exist.
  • intern returns the symbol with the given name that lives in the given package.
  • symbol-function returns the function object (a lambda abstraction, or more likely, its compiled representation) associated with the symbol.
  • And then funcall invokes that function. It is kind of clunky, but unfortunately there's not really a better way to mix calls which load code to create a package with names living in that package in the same file.
JohnMaraist
Thanks for the response. This is somewhat beyond my understanding of lisp. I am a young grasshopper in requirement of wax on wax off. When I run this, symbol-function says it requires only a single argument. How do I concatenate the package object to the symbol string? I'm assuming that's what's wrong.
Giles Roberts
Whoops! My bad --- forgot the call to `intern` to glue the function name and package together. It's edited to correct now.
JohnMaraist
Thanks a lot for the explanation. That's helped me with understanding what symbols and the difference with compile and run time are. I'm assuming If I were to start programming a real app this unpleasantness would be avoided by defining the code in a separate asd file?
Giles Roberts
@Giles Roberts Yes, that's what I'd recommend. When you then load (or compile) your package, ASDF will ensure that the systems you depend on are loaded (and, if necessary, compiled).
Vatine
Thanks. For a minute there I thought my eyes were going funny but it's just SO incorrectly syntax highlighting lisp code.
Giles Roberts