Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

package surgery library?

22 views
Skip to first unread message

Mirko Vukovic

unread,
Apr 25, 2012, 11:50:10 AM4/25/12
to
Hi,

I just wrote the following routine to remove all symbols from a package:

(defun unintern-package-symbols (package)
"Unintern symbols defined by PACKAGE"
(let* ((external-symbols
(remove-duplicates
(let ((syms nil))
(loop for package in (package-use-list package)
do (do-symbols (sym package)
(push sym syms)))
syms)))
(all-symbols
(let ((syms nil))
(do-symbols (sym package)
(push sym syms))
syms))
(package-local-symbols
(set-difference all-symbols external-symbols)))
(dolist (sym package-local-symbols)
(unintern sym package))))

But, this must have been done countless times, and it could even be part of a recommended and well maintained library. Is there such a library?

Thanks,

Mirko

Zach Beane

unread,
Apr 25, 2012, 11:58:01 AM4/25/12
to
Mirko Vukovic <mirko....@gmail.com> writes:

> Hi,
>
> I just wrote the following routine to remove all symbols from a package:

Why?

> (defun unintern-package-symbols (package)
> "Unintern symbols defined by PACKAGE"
> (let* ((external-symbols
> (remove-duplicates
> (let ((syms nil))
> (loop for package in (package-use-list package)
> do (do-symbols (sym package)
> (push sym syms)))
> syms)))
> (all-symbols
> (let ((syms nil))
> (do-symbols (sym package)
> (push sym syms))
> syms))
> (package-local-symbols
> (set-difference all-symbols external-symbols)))
> (dolist (sym package-local-symbols)
> (unintern sym package))))
>
> But, this must have been done countless times, and it could even be part of a recommended and well maintained library. Is there such a library?

I think you can simplify this like so:

(defun unintern-package-symbols (package)
(do-symbols (symbol package)
(unintern symbol package)))

I can't think of a use-case for such a function, though. What's yours?

Zach

Mirko Vukovic

unread,
Apr 25, 2012, 12:28:47 PM4/25/12
to
On Wednesday, April 25, 2012 11:58:01 AM UTC-4, Zach Beane wrote:
> Mirko Vukovic <...> writes:
>
> > Hi,
> >
> > I just wrote the following routine to remove all symbols from a package:
>
> Why?

I was not precise in my initial message. I want to remove the symbols created by the package, but leave the imported symbols alone.

Sometimes when I am developing a library, I change, for example, function names.

But if another function is still calling the old function name, it still compiles correctly, but calls the wrong function.

I would typically restart slime/lisp, but never liked that solution. I thought this would be a cleaner way:
- go to cl-user
- clean-up the package
- reload the library

>
> > (defun unintern-package-symbols (package)
> > "Unintern symbols defined by PACKAGE"
> > (let* ((external-symbols
> > (remove-duplicates
> > (let ((syms nil))
> > (loop for package in (package-use-list package)
> > do (do-symbols (sym package)
> > (push sym syms)))
> > syms)))
> > (all-symbols
> > (let ((syms nil))
> > (do-symbols (sym package)
> > (push sym syms))
> > syms))
> > (package-local-symbols
> > (set-difference all-symbols external-symbols)))
> > (dolist (sym package-local-symbols)
> > (unintern sym package))))
> >
> > But, this must have been done countless times, and it could even be part of a recommended and well maintained library. Is there such a library?
>
> I think you can simplify this like so:
>
> (defun unintern-package-symbols (package)
> (do-symbols (symbol package)
> (unintern symbol package)))

I think this will unintern also the imported symbols, which is what I'm trying to avoid.

>
> I can't think of a use-case for such a function, though. What's yours?
>
> Zach

Mirko

Zach Beane

unread,
Apr 25, 2012, 12:58:19 PM4/25/12
to
Mirko Vukovic <mirko....@gmail.com> writes:

> On Wednesday, April 25, 2012 11:58:01 AM UTC-4, Zach Beane wrote:
>> Mirko Vukovic <...> writes:
>>
>> > Hi,
>> >
>> > I just wrote the following routine to remove all symbols from a package:
>>
>> Why?
>
> I was not precise in my initial message. I want to remove the symbols
> created by the package, but leave the imported symbols alone.

The symbols available in a package via the use of another package (as
with use-package or the (:use ...) clause in defpackage) are not
imported, but inherited. They are not present in a package, and so are
not affected by unintern.

Importing is different. Strictly speaking, ALL symbols present in a
package are imported. In the simplest situation, an uninterned symbol is
imported, e.g. the following creates a symbol that prints as XXX::YYY:

(make-package "XXX" :use '())
(import (make-symbol "YYY") "XXX")

This makes XXX::CAR the EQ to CL:CAR:

(import 'cl:car "XXX")

Are you trying to get rid of the latter but not the former? Or did you
really mean only inherited symbols?

> Sometimes when I am developing a library, I change, for example, function names.
>
> But if another function is still calling the old function name, it still compiles correctly, but calls the wrong function.
>
> I would typically restart slime/lisp, but never liked that solution. I thought this would be a cleaner way:
> - go to cl-user
> - clean-up the package
> - reload the library

I kind of like the certainty of a fresh environment.

>> I think you can simplify this like so:
>>
>> (defun unintern-package-symbols (package)
>> (do-symbols (symbol package)
>> (unintern symbol package)))
>
> I think this will unintern also the imported symbols, which is what
> I'm trying to avoid.

It won't affect inherited symbols.

Zach

Alex Mizrahi

unread,
Apr 25, 2012, 1:21:33 PM4/25/12
to
> Sometimes when I am developing a library, I change, for example, function names.
> But if another function is still calling the old function name, it still compiles correctly, but calls the wrong function.

If you use defpackage, SBCL (for example) will warn you about such case.
You can handle that warning and unintern symbol.

I.e. make a macro which would wrap defpackage in handler-bind to catch
warning sent by SBCL and unintern symbol. Since it is only revelant
during development it doesn't need to be portable.

Alternatively, you can implement wrapper for defpackage which does this
without support from implementation. This is probably easier than you
think (about as complex as your uninterner function), check defpackage
code in SBCL for example.

E.g. function update-package-with-variance receives a list of exports.
But it gathers a list of old exports first:

(do-external-symbols (symbol package)
(push symbol old-exports))

Then it computes difference:

(setf old-exports (set-difference old-exports exports :test #'string=))

And warns if there is something in that difference,

> I would typically restart slime/lisp, but never liked that solution. I thought this would be a cleaner way:
> - go to cl-user
> - clean-up the package
> - reload the library

No, cleaner way is to restart. Nuking package is a lazier way.
It won't help when you define methods for GFs in other package, for example.

Clean environment is a clean environment.

Mirko Vukovic

unread,
Apr 25, 2012, 2:21:30 PM4/25/12
to
I was thinking of inherited symbols. I'll be reading hyperspec tonight.

Thanks,

Mirko

Daimrod

unread,
Apr 25, 2012, 4:44:19 PM4/25/12
to
Mirko Vukovic <mirko....@gmail.com> writes:

> Sometimes when I am developing a library, I change, for example, function names.
>
> But if another function is still calling the old function name, it still compiles correctly, but calls the wrong function.
>
> I would typically restart slime/lisp, but never liked that solution. I thought this would be a cleaner way:
> - go to cl-user
> - clean-up the package
> - reload the library

You can find every known functions which called this function in SLIME
with C-c C-w C-c (slime-who-calls SYMBOL) and then recompile them with
C-c C-k (slime-recompile-all-xrefs &optional RAW-PREFIX-ARG) or one of
them with C-c C-c (slime-recompile-xref &optional RAW-PREFIX-ARG).

Use C-c C-w C-h to find others slime-who-* functions.
0 new messages