Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does using defpackage result in a NAME-CONFLICT?

So I'm practicing lisp with Project Euler, and I'm collecting little utility functions into a separate file to reduce duplication, and I expect that it might get pretty huge, so I've gone ahead and made a package definition. Here is a condensed version of the file that still illustrates my problem:

(defpackage :euler-util
    (:use :common-lisp)
    (:export :divisible-by))

(in-package :euler-util)

(defun divisible-by (x y)
    (equal 0 (mod x y)))

I can compile and load (C-c C-k) that file into SLIME without any warnings or errors. Now, when I go to use it in another file, I do the following:

(load "util.lisp")
(use-package :euler-util)

(defun euler-1 ()
    (loop for i from 3 to 999 when (or (divisible-by i 3) (divisible-by i 5)) sum i))

When I try to compile and load THAT file, I get an error like this:

"USE-PACKAGE # causes name-conflicts in # between the following symbols: EULER-UTILS:DIVISIBLE-BY, COMMON-LISP-USER::DIVISIBLE-BY [Condition of type NAME-CONFLICT]"

Why is this symbol appearing in the COMMON-LISP-USER package, and how do I stop it?

like image 626
Lee Crabtree Avatar asked Feb 24 '14 22:02

Lee Crabtree


People also ask

What is name conflicts?

A naming conflict occurs when you try to create or use an identifier that was previously defined. In some cases, naming conflicts generate errors such as Ambiguous name detected or Duplicate declaration in current scope.

How name conflicts are resolved during package import?

A name conflict in use-package between a symbol directly present in the using package and an external symbol of the used package may be resolved in favor of the first symbol by making it a shadowing symbol, or in favor of the second symbol by uninterning the first symbol from the using package.


1 Answers

compile-file reads all the forms in the file, and only executes forms that expand into the appropriate eval-when expressions. In your example above, the util.lisp file is not loaded until after the referencing file is already read (interning all its symbols in cl-user). use-package is similarly a plain function call that is not evaluated until load time, and that's when you're asking it to make two distinct symbols by the same name accessible in the current package.

One option is to put the load and use-package statements in an eval-when form, e.g.

(eval-when (:compile-toplevel :load-toplevel :execute)
  (load "util.lisp")
  (use-package :euler))

I think it would be better to define a new package for your project, and put it at the top of your file:

(defpackage #:euler
  (:use #:cl #:euler-util))

(in-package #:euler)

Those statements are automatically evaluated at compile time, so there's no need for eval-when.

Experienced CL authors tend to avoid this problem by defining packages in a specific order, putting in-package forms in every source file, and by using a system definition facility to compile and load files in the right order.

I use ASDF as a system definition facility. A simple system file could look like this:

;;;; my-project.asd

(asdf:defsystem my-project
  :serial t
  :components ((:file "util")
               (:file "my-project")))

If you put that file somewhere ASDF knows about, (asdf:load-system "my-project") will then compile and load the files in the specified order.

If you use Quicklisp, one easy way to do it is put the project's directory in ~/quicklisp/local-projects/ and then use (ql:quickload "my-project") to automatically load it and its dependencies.

like image 159
Xach Avatar answered Sep 19 '22 18:09

Xach