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:
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?
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.
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