SLIME hints #2 – slime-compile-and-load-file vs other slime-compile functions

Development Consulting Articles

News

This is part of the series on SLIME functions. See the introduction for information on what SLIME is.

SLIME has a bunch of different functions that compile code from a file buffer into the running Lisp process.

I’ll list a few of them here, and end with why you normally want to use slime-compile-and-load-file instead of any of the other ones.

  1. slime-eval-last-expression (default key-binding “C-x C-e”) evaluates the expression right before point (the cursor). This is occasionally useful because it’s a quick way to evaluate part of a larger expression. For instance, say I’ve got this code, with | indication the cursor position:

    (defn connection-middleware [handler]
      (fn [request]
        (with-db *db*|
          (handler request))))
    

    When I call slime-eval-last-expression, the message line at the bottom of my Emacs screen shows the value of the var *db*.

  2. slime-compile-defun (default key binding: “C-c C-c”) evaluates the current definition (from the current cursor position downwards). It doesn’t have to be a function definition (at least not for clojure code); all of the common (def…) forms will work. This is useful if you made a quick update to a single definition and want to load it into the current process without loading anything else.

    In other words, given the earlier code and cursor position:

    (defn connection-middleware [handler]
      (fn [request]
        (with-db *db*|
          (handler request))))
    

    Calling slime-compile-defun will evaluate the whole connection-middleware function.

  3. slime-compile-region (no default binding) evaluates whatever you’ve currently selected.
  4. slime-compile-and-load-file (default binding: “C-c C-k”) compiles and loads the whole file.

    It’s the easiest method to compile stuff since you don’t need to have your cursor on any particular position, but the main reason to do this instead of, say, slime-compile-defun is that this gives you much more reasonable error messages.

    When you call any of the other compile functions, any errors you get back while compiling or later will not refer to a file and line number. This makes it a lot harder to find the error in your source code (even errors in other parts of the same file may now not refer to the right lines either, if you moved or resized your definition).

    In addition, compile errors will be noted using the standard M-n and M-p key bindings for compiler errors – in this case, using the functions (slime-next-note) and (slime-previous-note) respectively. These will navigate to the given error, and display the particular error on that line the echo buffer.

To recap, unless you want to evaluate a particular value in a source file or you’re working in a “scratch” buffer with all kinds of stuff in it, you generally want to compile the whole file as a unit, since it makes the most sense if anything goes wrong.

updates: Corrected the default binding of slime-compile-and-load-file. Thanks to Don Jackson for reporting the mistake.