Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading structures with typed slots in SBCL

Consider this simple code example:

(defstruct test
  (:example nil :type (simple-array single-float)))

(defparameter test-struct
  (make-test :example (make-array 10 :element-type 'single-float
                                     :initial-element 1.0)))

Nothing crazy here as we can see, a simple struct with a single slot is defined. We also specify that the :example slot is strongly type expected to be an array of single floats. No questions here, everything works fine.

Let us write the test-struct to a file now:

(with-open-file (out "~/Desktop/out.test"
             :direction :output
             :if-exists :supersede)
  (format out "~s" test-struct))

Again, no surprises, we get a nice little file on the desktop with the following contents:

#S(TEST :EXAMPLE #(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0))

Tension is starting to creep in, however, as we notice that nothing is suggesting that this particular literal array is supposed to contain single floats. With this suspicion, let us try loading this struct back:

(defparameter loaded-struct
  (with-open-file (in "~/Desktop/out.test")
    (read in nil)))

And here we are, SBCL happily drops us into a debugger:

SBCL drops into a debugger when attempting to read a typed array

The question is: is there a way to instruct SBCL to verify that this array slot in the structure is of a valid type and load it? Or in other words, is it possible to read structs with strongly typed slots back without resorting to building custom writers and constructors?

like image 579
Werdok Avatar asked Mar 09 '23 10:03

Werdok


1 Answers

It works if you print the object readably:

(equalp test-struct
        (read-from-string 
          (with-output-to-string (o)
            (write test-struct :readably t :stream o))))
=> T ;; no error while reading the structure back

The string is:

"#S(TEST
   :EXAMPLE #.(COERCE #(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0)
                      '(SIMPLE-ARRAY SINGLE-FLOAT (*))))"

If you want to use format, use ~W while *print-readably* is T.

like image 92
coredump Avatar answered Mar 16 '23 00:03

coredump