LISP - Structures
Lisp - Structures with defstruct
Section titled “Lisp - Structures with defstruct”Structures are user-defined, composite data types that group related data into a single object. They are the simplest and often most performant way to create record-like data in Common Lisp, ideal for when the full power of the Common Lisp Object System (CLOS) is not required.
Defining a Structure with defstruct
Section titled “Defining a Structure with defstruct”The defstruct macro is used to define a new structure type. When you define a structure, Lisp automatically generates a set of useful functions for creating and interacting with instances of that structure.
Let’s define a book structure to track library books:
(defstruct book title author subject (book-id -1) ; Providing a default value (available-p t))What defstruct Creates Automatically
Section titled “What defstruct Creates Automatically”- Constructor (
make-book): A function to create new instances of the structure. - Type Predicate (
book-p): A function that returnsTif its argument is abookstructure, andNILotherwise. - Accessors (
book-title,book-author, etc.): Functions to retrieve the value of a specific slot from a structure instance. - Setters: The accessors are
setf-able, allowing you to modify slot values. - Copier (
copy-book): A function to create a (shallow) copy of a structure instance.
Working with Structures: A Complete Example
Section titled “Working with Structures: A Complete Example”This example demonstrates the entire lifecycle: creating, accessing, modifying, and checking the type of a structure instance. We use let to keep our variables local.
main.lisp
Section titled “main.lisp”;; Define the book structure (should be at the top level of your file)(defstruct book title author subject (book-id -1) (available-p t))
(defun run-book-demo () (let ((book1 (make-book :title "The Pragmatic Programmer" :author "Andy Hunt & Dave Thomas" :subject "Software Engineering" :book-id 101)))
;; 1. Print the created structure (format t "Created Book:~% ~s~%~%" book1)
;; 2. Access slot values (format t "Title: ~s~%" (book-title book1)) (format t "Is available? ~a~%~%" (book-available-p book1))
;; 3. Modify a slot value using SETF (format t "Checking out the book...~%") (setf (book-available-p book1) nil) (format t "Is available now? ~a~%~%" (book-available-p book1))
;; 4. Use the type predicate (format t "Is book1 a 'book' type? ~a~%" (book-p book1)) (format t "Is the string \"hello\" a 'book' type? ~a~%" (book-p "hello"))))
;; Run the demonstration function(run-book-demo)Output
Section titled “Output”Created Book: #S(BOOK :TITLE "The Pragmatic Programmer" :AUTHOR "Andy Hunt & Dave Thomas" :SUBJECT "Software Engineering" :BOOK-ID 101 :AVAILABLE-P T)
Title: "The Pragmatic Programmer"Is available? T
Checking out the book...Is available now? NIL
Is book1 a 'book' type? TIs the string "hello" a 'book' type? NILAdvanced defstruct Options
Section titled “Advanced defstruct Options”defstruct provides options to customize its behavior, making it highly flexible.
:conc-name: Controls the prefix for accessor names.(:conc-name book-)is the default. Setting it tonilcreates accessors with no prefix (e.g.,titleinstead ofbook-title).:constructor: Customizes the constructor name, e.g.,(:constructor create-book). Ifnil, no constructor is created.:include: Allows a structure to inherit slots from another. This is a simple form of inheritance.:type: Specifies the underlying representation.(:type vector)creates a structure represented by a vector, which can be faster.(:type list)uses a list.
Example with :include and :conc-name
Section titled “Example with :include and :conc-name”;; Base structure(defstruct vehicle (num-wheels 4))
;; Car inherits from vehicle(defstruct (car (:include vehicle) (:conc-name car-)) make model)
(let ((my-car (make-car :num-wheels 4 :make "Honda" :model "Civic"))) (format t "My car: ~a, Make: ~a, Wheels: ~a" my-car (car-make my-car) ; Accessor from car (vehicle-num-wheels my-car) ; Accessor from included vehicle ))Structures vs. Classes (CLOS)
Section titled “Structures vs. Classes (CLOS)”When should you use defstruct versus defclass?
- Use
defstructfor: Simple data containers, performance-critical code where you need packed data, and when you don’t need features like multiple inheritance or method specialization. - Use
defclassfor: Complex object models, systems requiring multiple inheritance, dynamic behavior with generic functions (multimethods), and introspection via the Metaobject Protocol (MOP).