Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common Lisp: Why is cl lnterning symbols to the wrong package when reading from file?

Tags:

common-lisp

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.

like image 722
robbyphillips Avatar asked Feb 22 '11 17:02

robbyphillips


2 Answers

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)))
  ...)
like image 60
Xach Avatar answered Oct 27 '22 13:10

Xach


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.

like image 26
Rainer Joswig Avatar answered Oct 27 '22 14:10

Rainer Joswig