Skip to content
An abstract class for serializable CLOS objects.
Common Lisp
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


This library provides an abstract class for serializing CLOS objects in a FASL file.

  • It exposes serializable-object class, save generic function and load-instance function. An instance of serializable-object has a slot pathname.
  • The implementation focuses on simplicity and conformance rather than speed.
  • It carefully combines the behavior of make-load-form and the file compiler specified in CLHS.
    • This guarantees the correct behavior for storing and loading the references (e.g. cyclic reference, displaced arrays)
  • Should be thread-safe.
  • :compression t compresses the fasl file, similar to the numpy .npz format.

TODO: The current implementation stores an object into a fasl file, whose format is implementation-dependent (and also version dependent). Future work could instead use an existing CLOS object serializer.

We do not use them currently for various reasons: First, the existing serializers are incomplete and unreliable; They are not as thoroughly tested as the default serialization performed in compile-file and load, which is required by the standard and is provided by each Lisp implementation.

The strongest selling point of this library is this reliability, with the cost of being restricted to the FASL-compatible lisp versions.

TODO: This library was originally written as a MOP abstract class. However, the initial implementation with MOP was not working as intended and I decided to switch to the easier solution due to the timeframe. In the future, we will pursue the API where make-instance can take :path and other keywords which are used for loading an instance if necessary.


(ql:quickload :serializable-object)
(in-package :serializable-object)

(defclass my (serializable-object)
  ((value :initarg :value :initform nil)))

(defparameter *my-instance* (make-instance 'my :value 5))

(save *my-instance* :verbose t :pathname "/tmp/tmp")
;; => Saving object #<MY {100E9DDC83}> to /tmp/tmp 
;; => Writing a magic code to /tmp/tmpAAURSO1.tmp 
;; => ; compiling file "/tmp/tmpAAURSO1.tmp" (written 12 MAR 2019 12:54:04 PM):
;; => ; compiling (INITIALIZATION-FORM)
;; => 
;; => ; wrote /tmp/tmp.fasl
;; -> ; compilation finished in 0:00:00.004
;; -> #P"/tmp/tmp.fasl"
;; -> ()

(defparameter *another-instance* (load-instance 'my :verbose t :pathname "/tmp/tmp"))
;; => ; loading #P"/tmp/tmp.fasl"

(print (slot-value *another-instance* 'value))
;; => 5



Abstract class.

 Generic function (save instance &key pathname store verbose parents)
   (save (serializable-object))
   (save :around (serializable-object))

Save an instance to a FASL file using the value of PATHNAME slot in the instance. When PATHNAME is given as an argument,

  • the object is stored in the file specified by PATHNAME,
  • the slot value is temporarily set to this value while saving the instance,
  • and the value of PATHNAME is used to save the PATHNAME slot in the saved object.

If STORE is non-nil when PATHNAME is given, PATHNAME also overwrites the slot value in the runtime object. Otherwise the PATHNAME slot value is restored to the original value after returning from this function.

If PARENTS is non-nil (default: t), ENSURE-DIRECTORIES-EXIST is called to ensure that the path exists.

When an error occurs during the call to SAVE (e.g. nonexisting directory or permission error), the path is reverted to the original value.

How it works:

  1. SAVE generic-function stores a single line of macro (initialization-form) to a temporary file and compiles a file under the dynamic environment where a special variable instance is bound to the object to be stored.
  2. The file compiler expands the macro to the code that sets instance to the value of instance. MAKE-LOAD-FORM expands the value into a loadable form.
  3. To load the instance, LOAD-INSTANCE function sets up a dynamic binding for instance and load the compiled file in this dynamic environment. The compiled code sets the newly created object (by evaluating the form produced by make-load-form) to instance. LOAD-INSTANCE retrieves this value.
Function (load-instance class &key pathname (if-does-not-exist t) verbose &allow-other-keys)

Load an instance from a file.

  • When IF-DOES-NOT-EXIST is non-nil (default), it checks the file existence.
  • When IF-DOES-NOT-EXIST is nil and the file does not exist, it calls MAKE-INSTANCE with the specified arguments.
  • When verbose is non-nil, it writes messages to the standard output.
  • It always checks if the loaded object is of the specified class.

Related Work


  • documentation : poor
  • tutorial : none
  • performance : unknown
  • scope / usability : all CLOS objects
    • cyclic references?
    • displaced arrays?


  • documentation : poor
  • tutorial : good
  • performance : unknown
  • scope / usability : hash table only


  • documentation : minimal
  • tutorial : none
  • performance : unknown. to a 32bit int stream
  • scope / usability : All CLOS class.
    • arrays?
    • cyclic references?
    • Exported slots can be customized, all slots by default.
    • Consideres the class slots.


  • documentation : minimal (source code) good (tutorial)
  • tutorial : good
  • performance : unknown. to a string that consists of a list
  • scope / usability :
    • needs to specify class-persistent-slots.
    • cyclic refernces?
    • displaced arrays?
    • Exported slots can be customized, needs to be specified for each class.
    • no consideration for class slots.


  • documentation :
  • tutorial :
  • performance :
  • scope / usability :
    • very specific. needs to be declared as defpvar


  • documentation :
  • tutorial :
  • performance :
  • scope / usability :
    • offers the versioning system
    • but heavily depends on ContextL.


  • documentation :
  • tutorial : there is an extensive tutorial, but the idea seems too complicated.
  • performance :
  • scope / usability :


This library is at least tested on implementation listed below:

  • SBCL 1.4.12 on X86-64 Linux 4.4.0-142-generic (author’s environment)

Also, it depends on the following libraries:

  • alexandria by Nikodemus Siivola <>, and others. : Alexandria is a collection of portable public domain utilities.
  • closer-mop
  • bordeaux-threads

Author, License, Copyright

Licensed under LGPL v3.

Copyright (c) 2019 Masataro Asai ( Copyright (c) 2019 IBM Corporation

You can’t perform that action at this time.