0

I am learning to define a system and have made a small testing package named test. It's structure looks like the following:

test/
  test.asd
  hi.lip
  hito.lisp
  package.lisp

Now in package.lisp file i define my package:

(in-package :cl-user)

(defpackage :test
  (:use #:cl)
  (:import-from #:uiop
        #:strcat)
  (:export #:sayhito))

and in test.asd the system:

(defsystem test
  :name "Testing"
  :components ((:file "package")
           (:file "hi")
           (:file "hito")))

In hi.lisp i have a helper function sayhi which isn't meant to be external:

(in-package :test)

(defun sayhi () "Hi")

and in hito.lisp the external function of the system hito:

(in-package :test)

(defun sayhito (name)
  (strcat (sayhi) " " name "!"))

I also have a directory /home/amir/lisp-link-farm/ where i put symbolic links of all my ASDFs into. Then in my lisp initialization file (.sbclrc) i have pushed this path into asdf:*central-registry*:

;;; The following lines added by ql:add-to-init-file:
#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"
                                   (user-homedir-pathname))))
  (when (probe-file quicklisp-init)
    (load quicklisp-init)))


;; where i am restoring symlinks to systems
(require 'asdf)
(push #p"/home/amir/lisp-link-farm/" asdf:*central-registry*)

Now when i load the test system by (ql:quickload :test) and change the package to (in-package :test) the internal helper function hi is also accessible as an external symbol! I can just do:

(sayhi)   ;; -> "Hi"

But if i don't change the package (so without (in-package :test) in the REPL) trying to call (test:sayhi) lisp complains that sayhi is not an external symbol in package test, while (test:sayhito "Lisp") works as it should. Why is this happening and what am i doing wrong? Any help is appreciated.

  • related: https://stackoverflow.com/questions/47782593/external-vs-internal-symbols-in-common-lisp-package/47790600#47790600 – Ehvince Sep 04 '19 at 12:57

2 Answers2

3

No, it is not accessible as an external symbol. As you wrote yourself, you changed the package to the package in question, and that means that it is your current package, and all symbol resolution works internally. It is just the same as when you write code in a specific package: you can refer to all symbols of the package without prepending the package.

Note that even if you changed your current package to test, referring to test:hi (with a single colon) signals an error.

So, you are not doing anything wrong, except expecting that the REPL somehow had other package resolution rules than a source file.

Svante
  • 50,694
  • 11
  • 78
  • 122
  • 1
    So the end user of my system should just `(ql:quickload :test)` without `(in-package :test)` and then use qualified names to use external symbols? Since otherwise they could accidentally overwrite symbols of my package? –  Sep 04 '19 at 11:25
  • 2
    There are two cases: library and interactive system. The former is much more common; here you selectively import from the package using the library, if at all. If you use the REPL as a user interface for an interactive system, you typically provide a `test-user` package that imports the public symbols of `test`. Widely used are `cl-user` and `asdf-user`, for example. – Svante Sep 04 '19 at 12:28
3

It seems you're doing alright. If you export a function, you can access it with package:function (test:sayhito) (a colon). If you don't export it, you can still access it with a double colon: package::function (test::sayhi).

When you are inside a package, well, you can directly type all symbols, exported or not, that's the goal.

Ehvince
  • 17,274
  • 7
  • 58
  • 79