lispcommon-lispquicklisp

Common Lisp - name clash I thought the package system was supposed to protect me against


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:

  1. 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?

  2. 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!


Solution

  • 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:

    Any 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.