Over the weekend, I had a name clash that was very hard to track down, but I managed to boil it down to a short example - thing is, I thought the package system was supposed to protect me from this, so I'm wondering how it can in future.
If I do this:
(ql:quickload "cl-irc")
(defpackage #:clash-demo
(:use #:cl
#:cl-irc))
(in-package #:clash-demo)
;; This is the name that clashes - I get a warning about this if I compile
;; this interactively (i.e. from slime) but not if I quickload the whole project.
(defun server-name (server)
(format nil "server-name ~a" server))
;; This needs an IRC server to work - if you have docker
;; then this will do the trick:
;;
;; docker run -d --rm --name ircd -p 6667:6667 inspircd/inspircd-docker
(defparameter *connection*
(cl-irc:connect :nickname "clash-demo"
:server "localhost"
:port 6667
:connection-security :none
:username "username"))
After the above, I get the following warning when defining server-name
:
WARNING: redefining CL-IRC:SERVER-NAME in DEFUN
And the following error if I try and print *connection*
(in my more full-fledged project I got a missing slot in a class that I'd defined - I think the root cause of both the problem I found and the minimal example above is the same though):
Control stack guard page temporarily disabled: proceed with caution
While I get the warning if I define things interactively, in practice I moved a bunch of code into a quickproject:make-project
'd and ql:quickload
-ed it, which I think silenced the warning as it always loaded cleanly, hence why it took me so long to track down the name clash.
My questions are:
Isn't the package system supposed to protect me from this? I think I can sort of see why the above happens - the reader's already seen the symbol server-name
so it thinks I'm referring to the already defined cl-irc:server-name
, and re-uses that - but surely the package system should somehow allow me to work around this?
I'm assuming the warning when I quickload
-ed the project was silence because quickload
assumes I don't want to see warnings from projects, is there a way I can make this more forceful when I load projects I'm making so that it raises an error, or at least warns me of these name clashes? For all I know there are a bunch more that just haven't caused me a problem yet.
I was expecting either (i) the names not to clash (i.e. my file would define the symbol clash-demo:server-name
, not re-use cl-irc:server-name
and cause it to be redefined) or (ii) this to be an error, or at least a warning when I quickload
the project.
Thanks very much in advance for any advice!
Suppose you really like packages A
and B
and want to :use
both of them in your package MINE
. They have a hundred external symbols each and you don't want to have to type any package prefixes. However, they both export a symbol with the same name, a:frob
and b:frob
. If you simply :use
them, you will get a symbol conflict.
To resolve the conflict, there are three options to decide what to do when you're in package MINE
and you refer to the unqualified symbol frob
:
A
so it refers to the the symbol a:frob
: (defpackage mine (:use a b) (:shadowing-import-from a frob))
B
so it refers to the symbol b:frob
: (defpackage mine (:use a b) (:shadowing-import-from b frob))
mine::frob
: (defpackage mine (:use a b) (:shadow frob))
- then, to use one from A or B you must write a:frob
or b:frob
explicitlyAny of these three cases may be preferable depending on your situation. Common Lisp will not automatically choose one for you. I think this is a reasonable design choice.