lexical binding lost when switching package - common-lisp

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?

Switching packages in a form has no direct effect on the form
Let's look at this:
(in-package "FOO")
(let ((x 10))
(in-package "BAR")
(setf x 20))
Which x does it set to 20? FOO::X or BAR::X?
Well, it is FOO::X. Switching packages during execution has no effect on the symbols already read. The whole let form is read at once and the *package* value is used for that. Having an IN-PACKAGE in the form itself has no effect on the form itself.
Symbol with a package prefix
If you want to use a symbol in a certain package, just write the package prefix:
cl-user:foo ; if FOO is exported and the package exists
or
cl-user::foo ; if foo is not exported and the package exists
for example:
(defun cl-user::cd (...) ...)
Computing with symbols
You can also compute new symbols in packages you don't know yet:
(let ((sym-name "A-NEW-SYMBOL")
(my-package-name "SOME-EXISTING-PACKAGE"))
(intern sym-name my-package-name))
If the package does not exist, you can create it.
You can also set the function of a computed symbol:
(setf (symbol-function (compute-a-function-symbol))
#'(lambda ()
'foo))

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.

IN-PACKAGE is a macro, not a function. The problem in your code is that saying (in-package cur-pck) tries not to switch into the package denoted by the cur-pck variable but to the package named CUR-PCK (which obviously does not exist).
You can set the package temporarily with
(let ((*package* (find-package :cl-user)))
(defun cd (dir)
...))
But then again, the easiest way to achieve what you are doing would be
(defun cl-user::cd (dir)
...)
which totally eliminates the need to set the current package.

Related

Export / unintern and symbol access

In the following example, I'm getting an error:
These symbols are not accessible in the COMMON-LISP-USER package:
(FOO::BAR)
yet,
LS-USER> (describe 'foo::bar)
FOO::BAR
[symbol]
; No value
Here's what how I got there:
CL-USER> (make-package "FOO" :use '())
#<PACKAGE "FOO">
CL-USER> (intern "BAR" *)
FOO::BAR
NIL
CL-USER> (export (find-symbol "BAR" (find-package "FOO")))
Now I understand what the error means and what I'm curious about is: "Is this behaviour correct according to the spec?". I'm using SBCL.
I can see why it's not accessible via foo:bar (it's not exported). However since export is given both the symbol and the package, why can't it access this symbol and export it? I'm seeing similar things with unintern.
A close read says "export makes one or more symbols that are accessible in package ...". It doesnt' say it has to be accessible in the current package (*package*).
It seems to me that export has all the information it needs to perform the export, but the only way this seems to work is with (export 'foo::bar (find-package "FOO")). Perhaps it's an underspecified area and this is just what SBCL has choosen to do?
This is entirely correct behaviour: anything else would be nonconformant. (export s) will try to export the symbols designated by s from the current package (the default for the optional second argument of export), which is CL-USER in your case. To do that those symbols must already be accessible in the current package. A symbol is accessible in the current package if:
either it is directly present because
it either has the current package as its home package
or it has been imported into it from some other package,
or it is accessible by inheritance due to the current package using some other package.
In the final case it will first be imported and then exported.
None of these things is true in your case. The symbol you are designating, which is FOO::BAR since symbols designate themselves, is not accessible in the CL-USER package at all.
See the spec

Referring to global symbols

I want to create a source file in which most of the functions there defined, are local to that source file. It's the same purpose that would be served in C by marking the functions static; in C++ one could also surround them with namespace { ... }. I get the impression in Lisp, the package system is the appropriate tool. However, my attempts so far are not working.
This is what I currently have, but SBCL rejects it with the claim that global-fun is undefined. Explicitly referring to it as cl-user:global-fun, produces similar results. What should I be doing?
(defun global-fun ()
(format t "global~%"))
(defpackage :local-package
(:use :common-lisp)
(:use :cl-user))
(in-package :local-package)
(defun local-fun ()
(global-fun)
(format t "local~%"))
You're nearly there. You might use Slime's autocompletion to find out.
Either export global-fun, or access it with a double colon: (cl-user::global-fun).
With another global-package:
(defpackage :global-package
(:use :common-lisp) ;; <-- can be :cl
;; (:use :cl-user) <-- not necessary
(:export :global-fun))
(in-package :global-package)
(defun global-fun () …)
(defpackage :local-package
(:use :cl
:global-defun)) ;; <-- one ":use" is possible
(in-package :local-package)
; etc
There seem to be some misconceptions here.
There is no such thing as a “global function” in Common Lisp. The thing you defined first in your file, global-fun is in some package, most likely the cl-user package.
There is also no direct correspondence between packages and files. You can define things for different packages in a single file, and you can define things for a single package in multiple files. To make things unambiguous and easy to read, there is a very sensible convention to always start a source file with an in-package form (in some styles preceded by a defpackage form), and to never put another in-package somewhere later in the file.
When you write a symbol without package, e. g. somefun or myarray, it is interned (i. e. a sort of idempotent registration) into the current package (see below what that is). This is independent from whether you currently define something or refer to it, because it is done by the reader when reading your source code forms. In both of the following forms, the symbol named foo is interned into the current package (and both result in the identical symbol to be used):
(defun foo ()
…)
(foo)
In order to refer to a symbol from a different package, you need to put the package name as a prefix with :: as separator, as in my-package::foo, but this is usually a code smell because…
… you should export any symbols that a user of your package is intended to use, from your package definition:
(defpackage my-package
(:use common-lisp)
(:export foo))
You can refer to exported symbols from another package with a single colon as separator, as in my-package:foo, and this is good style.
Now, the current package is just the value of the variable *package*. If you look at it from the point of view of a REPL session, this is the argument of the most recent in-package call. In the context of whole file compilation, it is the value of the lexically closest preceding in-package form. In the context of single-form compilation in a file, the IDE will (in any case I have seen) look for that preceding in-package form even if it is not evaluated explicitly. In a pristine Lisp image, the starting package is common-lisp-user, which has a nickname cl-user.

Common lisp about naming packages and using them

I try to use Common Lisp packages, but I have several (probably naming conventions) problems, first is the use of "#:" it seems not necessary but is like sharp-quote in functions that is better to use depending on your context.
(defpackage #:match-test
(:use #:match
#:fiveam
#:cl)
(:export #:run!
#:test-match)
(:documentation "Test package for testing match project 1 of CS202"))
Then is in how to use that package
(in-package #:match-test)
(in-package :match-test)
(in-package match-test)
it works, but when I want to delete that package it only works with:
CL-USER> (delete-package (in-package #:match-test))
#<BOOLEAN <<error printing object>> {2010004F}>
it gives that error, but it makes the job done. It seems working with the package as an object, I also do not understand the hyperspec, is a problem that I need to learn CLOS, that is true I'm a beginner learning Lisp, but I suppose that I can get a easy clarifying for my doubts.
I hope that I said it quite clearly.
Finally I want to say that I used emacs + sly + roswell and
CL-USER> (lisp-implementation-type)
"SBCL"
CL-USER> (lisp-implementation-version)
"1.4.6"
DEFPACKAGE and IN-PACKAGE are defined as macros. They take a literal name - a string designator: foobar, |FOOBAR|, #:FOOBAR, :FOOBAR or "FOOBAR".
DELETE-PACKAGE is a function and expects a string designator, too. But since it is a function, the argument is evaluated. This means: if you want to pass the name, you have to quote it - if it is a symbol not in the keyword package. Strings and keyword symbols are self-evaluating and don't need to be quoted. Valid arguments to DELETE-PACKAGE are for example:
'foobar
'|FOOBAR|
'#:FOOBAR
:FOOBAR or ':FOOBAR
"FOOBAR" or '"FOOBAR"
Since DELETE-PACKAGE is a function, the argument gets evaluated -> you can also evaluate variables, function calls, ... as argument.
The Error: Deleting the current package
LispWorks:
CL-USER 43 > (delete-package (in-package #:match-test))
Error: Cannot delete the current package, #<The MATCH-TEST package, 0/16 internal, 2/16 external>.
1 (abort) Return to top loop level 0.
SBCL:
* (delete-package (in-package #:match-test))
debugger invoked on a SIMPLE-TYPE-ERROR in thread
#<THREAD "main thread" RUNNING {10005605B3}>:
*PACKAGE* can't be a deleted package:
It has been reset to #<PACKAGE "COMMON-LISP-USER">.
Your code tries to delete the current package - you just used IN-PACKAGE to make it the current package - deleting the current package is usually not a good idea. You are shooting yourself in the foot. A Lisp might prevent that (like my example in LispWorks) or allow it - but then you have to live with the consequence.

How to export all definition symbols in a file in Common Lisp?

My lisp file contains about 50 function and macro definitions. At the head of the file is:
(defpackage :utils
(:use :common-lisp))
(in-package :utils)
; ... ~50 defuns/defmacros follow along with some other code
I want to export all these 50 definitions. But no other symbols.
To write them all out in :export clauses inside defpackage seems very tedious.
I tried getting the necessary symbols by using loop's facility for listing symbols in a package. But both "symbol" and "present-symbol" don't output the needed definition symbols. I could somehow subtract "external-symbols" and inherited symbols. But this seems like the kind of thing everyone would need and there should be an established easy solution. I looked around and haven't found a straightforward answer.
How do I export all the definition symbols without having to write them out individually and manually?
scan symbols
You can scan all symbols and export all that have a function binding (this includes macro names):
(defun export-fbound-symbols (package)
"export symbols with function bindings"
(do-symbols (s package)
(when (fboundp s)
(export s package))))
This is usually not a very good idea: good software engineering practice is to limit the set of public interfaces.
be more selective
You can redefine defun and defmacro so that they automatically export their definienda.
See exporting.lisp in CLISP. E.g.,
(defmacro define-function (name lambda-list &body body)
`(progn
(export ',name)
(defun ,name ,lambda-list ,#body)))
Note that this ignores the possibility of (defun (setf foo) (...) ...).
No, this is not something everyone needs. Usually, you'd export them as you write (and actually need) them.
I'd probably use an ad hoc keyboard macro for this. You could also write a little Lisp function to read your file form by form and output the relevant symbols for copy-paste.

Bulk `unintern` for renamed exported symbols

I use packages a lot and the exported symbols often change their names. When I try to recompile the package I get warnings like this:
package.lisp:3:1:
warning:
MY-PROJECT also exports the following symbols:
(OLD-SYMBOL1 OLD-SYMBOL2 OLD-SYMBOL3)
See also:
Common Lisp Hyperspec, DEFPACKAGE [:macro]
SBCL Manual, *ON-PACKAGE-VARIANCE* [:variable]
--> EVAL-WHEN
==>
(SB-IMPL::%DEFPACKAGE "MY-PACKAGE" '("KE") 'NIL 'NIL 'NIL '("CL") 'NIL
'NIL '("NEW-EXPORTED-SYMBOL1" "NEW-EXPORTED-SYMBOL2") '("MY-PROJECT") 'NIL
...)
I know that I can use (unintern 'old-symbol1) to signal the system I don't want to use that symbol anymore. However this is becoming very tedious when there is a lot of renaming.
My questions are:
1) Is is possible to signal to sbcl or emacs to unintern the old/previously exported symbols automatically?
2) If not - is it possible to get all "old" symbols in a variable?
My plan for 2) is to make a key binding to something like (apply #'unintern *old-symbols*)
Setting the variable *on-package-variance* to a list (:error t) will give you an error instead of a warning when redefining the package. The error will have a restart DROP-THEM to unexport the symbols.
You can add
(setf *on-package-variance* '(:error t))
to your ~/.sbclrc to have it always set when starting up SBCL.
First I don't think you want to unitern symbols. Unintern removes them from the package. I think you want to unexport them to avoid the warning. You can do that with the following function
(defun unexport-package-symbols (package)
(do-symbols (symbol package)
(destructuring-bind (symbol status)
(find-symbol (symbol-name symbol) package)
(when (eq status :external)
(cl:unexport symbol package)))))
;; It takes a package-designator as an argument.
(unexport-package-symbols "MY-PACKAGE")

Resources