common-lisppackageswank

lexical binding lost when switching package


All I wanted was to load an initialisation file for swank which wouldn't affect my lisp when it's started without swank...

I first tried #+swank (defun...) in my file that's loaded from ccl-init (trying this on ccl 1.10 + windows), and soon realised it's sourced before swank is loaded (obviously).

My aim is to define a simple function in :cl-user everytime I start swank. I just ended up with a swank add-hook to load my init.lisp file, and since I want to define the function in cl-user, I tried this in the init.lisp:

(let ((current-package *package*))
  (in-package :cl-user)
  (defun cd (dir)
    (swank:set-default-directory
      (parse-namestring dir)))
  (in-package current-package))

Now, I don't recall if a defun in let was allowed, but lisp doesn't complain for it, but rather tells me that cur-pck symbol doesn't exist, and it seems when we switch the package, cur-pck binding gets out of scope. I thought cur-pck is a lexical binding, and that it should be reachable from within the lexical region, being independent from a package, am I wrong?

Why do I switch packages? I'm thinking that loading this file from swank at some initialisation point will define things in some swank package, that's why I wanted to try switching to cl-user first, define the function symbol, and switch back to let swank do it's thing.

At this point I guess I need someone to tell me I'm approaching the problem from the wrong angle, and that I should better choose an easier solution.

Additionally, out of curiosity in case above is the complete wrong approach, is there a way to define a symbol in another package within a function or a closure?


Solution

  • If you want to define a function in a different package that the current one you can use a qualified symbol for a name

    (defun cl-user::cd (dir)
        (swank:set-default-directory
          (parse-namestring dir)))
    

    The binding is not being "lost". To test so yourself add (princ cur-pck) before the in-package form.

    If you try evaluating (in-package *package*) you will see why your code fails to switch packages. The in-package macro does not evaluate its argument. The code that would give us the code we would want to evaluate is:

    (let ((cur-pck *package*))
      (in-package :cl-user)
      (defun cd (dir)
        (swank:set-default-directory
         (1+ 2)))
      (princ cur-pck)
      `(in-package ,cur-pck)) 
    

    However, as Rainer Joswig noted in his answer the in-package has no effect on forms already read, so it wouldn't work as desired even as a macro.

    A style nitpick, don't use abbreviations, write current-package.