Ignacio
Ignacio

Reputation: 367

Access constant defined in a file loaded with load

I have this lisp file:

(load "constants.lisp")

(defpackage :my-package
  (:use :cl))

(in-package :my-package)

(format t "Constant value: ~A~%" my-constants:+my-constant+)

And this is constants.lisp (same directory):

(defpackage :my-constants
  (:use :cl)
  (:export :+MY-CONSTANT+))

(in-package :my-constants)

(defconstant +MY-CONSTANT+ "some value")

I get this error when I do C-c C-k on Sly:

There is no package named "MY-CONSTANTS" .
[Condition of type CCL::NO-SUCH-PACKAGE]

How can I load some constant defined in other file? Something like import in other languages. Thanks!!

Upvotes: 2

Views: 38

Answers (1)

Gwang-Jin Kim
Gwang-Jin Kim

Reputation: 9990

C-c C-k Is A Compiling Command

The problem is that C-c C-k does not run the file, but compiles it.

So to ensure the loading is executed at compile level, you have to load by:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (load "constants.lisp"))

C-c C-l re-loads the file

But I think what you actually wanted to do is sly-load-file just loading the current file.

This you can do by: C-c C-l and press RETURN when it asks for whether to load this current file's path.

And then, it should work with the simple (load "constants.lisp") without the eval-when expression around it!

The only annoying thing will be that you are loading a constant - and therefore it will first activate the handler system (like and error) and ask you what to do, since you are re-loading a constant (constants are not thought to be changed during a session thus also not re-defined).

Perhaps Don't Use A Constant?

If it is not absolutely necessary to declare it as a constant, I would just use (defparameter *my-constant* "my value") and treat it as a special variable which you - by your own convention - doesn't change any more for the rest of the session.

Or, you define (defvar *my-constant* "my value") and the next time defvar on the same variable is run - it will be ignored - so it is some kind of a constant - no reloading of the variable.

Use ASDF To Control Loading Fully

When you are trying to write a package which loads the my-constants package, then you should use asdf.

With a project structure like

my-project/
│── my-project.asd       # ASDF system definition
│── my-constants.lisp    # Constants package
│── my-package.lisp      # Main package
└── main.lisp            # Entry point (optional)

and my-project.asd:

(asdf:defsystem "my-project"
  :description "An example ASDF system with multiple files"
  :version "0.1"
  :author "Your Name"
  :license "MIT"
  :depends-on ()
  :serial t      ;; loading of files in the given order:
  :components ((:file "my-constants")
               (:file "my-package")
               (:file "main")))

my-constants.lisp:

(defpackage :my-constants
  (:use :cl)
  (:export +MY-CONSTANT+))

(in-package :my-constants)

(defconstant +MY-CONSTANT+ 42)

my-package.lisp:

(defpackage :my-package
  (:use :cl :my-constants))

(in-package :my-package)

(defun print-constant ()
  (format t "Constant value: ~A~%" +MY-CONSTANT+))

And finally main.lisp with the final package:

(defpackage :my-project
  (:use :cl :my-package))

(in-package :my-project)

(defun main ()
  (format t "Running my-project...~%")
  (print-constant))

;;; Call main automatically when loading:
(main)

Or use if you want to use from main.lisp also the constants:

(defpackage :my-project
  (:use :cl :my-package :my-constants))

(in-package :my-project)

(defun main ()
  (format t "Running my-project...~%")
  (print-constant)
  (format t "Constant: ~A%~%" my-constants:+MY-CONSTANT+))

;;; Call main automatically when loading:
(main)

Manually enforce loading of the file

The most primitive solution and simplest solution would be to manually load both files.

my-loader.lisp:

(load "my-constants.lisp")
(load "my-package.lisp")

my-constants.lisp:

(defpackage :my-constants
  (:use :cl)
  (:export +MY-CONSTANT+))

(in-package :my-constants)

(defconstant +MY-CONSTANT+ 42)

my-package.lisp:

(defpackage :my-package
  (:use :cl :my-constants))

(in-package :my-package)

(defun print-constant ()
  (format t "Constant value: ~A~%" +MY-CONSTANT+))

And then finally call in the REPL:

(load "my-loader.lisp")
;; and then you can call
(my-package::print-constant)  ;; since not externalized, we use `::`

Upvotes: 3

Related Questions