First, I am very new to lisp, so it is possible that I'm just missing something very obvious. That said, I have Practical Common Lisp open next to me and the CL Hyper Spec open in the next tab, and have been unable to solve this issue:
I am trying to read a tree from a file, and assign values to slots in a class using this code:
(defun load-char (file)
(with-open-file (in file)
(with-standard-io-syntax
(let ((chr-in (read in))
(chr (make-instance 'pc)))
(mapcar #'(lambda (x) (setf (slot-value chr (car x)) (cdr x))) chr-in)
chr))))
When I originally hacked this together and ran it under the cl-user package everything worked perfectly -- I was quite proud of myself, actually. The problem started when I packaged this along with my class definition and a few helper functions in a new package. I loaded the package using asdf, then used (in-package :package-name)
to change my REPL's active package.
Now when I run (load-char "/path/to/file")
I get an error that says the COMMON-LISP-USER::ID
(ID is the first slot in my pc class) does not exist, so I wrote this to see what I was actually getting when I read the file in:
(defun load-char-test (file)
(with-open-file (in file)
(with-standard-io-syntax
(let ((chr-in (read in))
(chr (make-hash-table)))
(mapcar #'(lambda (x) (setf (gethash (car x) chr) (cdr x))) chr-in)
(maphash #'(lambda (k v) (format t "~a: ~a~%" k v)) chr)
chr))))
Then in the REPL I do (defparameter hsh (load-char-test "/path/to/file"))
and everything goes without errors, and my format call returns exactly what I expect (SLOT: VALUE). But when I do a (gethash 'id hsh)
it returns NIL NIL
. But, when I do (gethash 'common-lisp-user::id hsh)
it returns the expected value.
So, I'm reading in everything just fine, but everything in my list is being interned under the COMMON-LISP-USER package instead of the one I defined, and I cannot figure out why. Help is greatly appreciated.
P.S. Sorry if this post is needlessly long, I just wanted to show that I had actually tried to figure this out myself.
Symbols created by READ
are interned in the package that is the current value of *PACKAGE*
at runtime, not the value *PACKAGE*
had when the code that calls READ
was defined. One option, then, is to wrap your reading forms in a form that binds *PACKAGE*
, e.g.
(let ((*package* (find-package :package-name)))
...)
Note that WITH-STANDARD-IO-SYNTAX
binds the variable *PACKAGE*
to the package CL-USER
.
You need to bind the variable *PACKAGE*
inside that macro using LET
to the package you wish to use.
Note also that WITH-STANDARD-IO-SYNTAX
binds the variable *READ-EVAL*
to T
. Which for security reasons usually is not what one might want as default. Again, change that via a LET
binding.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With