LISP - Structure Types
Lisp - Structure Types with defstruct
Section titled “Lisp - Structure Types with defstruct”In Common Lisp, defstruct is a macro used to define simple, efficient, record-like data structures. It provides a convenient way to group related data into a single object with named slots. defstruct automatically generates a constructor, accessors, and other utility functions for your new data type.
Defining a Basic Structure
Section titled “Defining a Basic Structure”The simplest defstruct defines a new type and its slots. Lisp then creates a suite of functions to work with it.
Example: A book Structure
Section titled “Example: A book Structure”main.lisp
Section titled “main.lisp”;; Define a structure named 'book' with four slots.(defstruct book title author subject id)
;; Create an instance of the 'book' structure.;; The constructor 'make-book' is automatically created for us.;; Using keyword arguments is the standard, readable practice.(let ((book1 (make-book :title "The Pragmatic Programmer" :author "Andy Hunt & Dave Thomas" :subject "Software Engineering" :id 9780201616224)))
;; Access the slots using the automatically generated accessors. ;; The accessor format is 'structure-name'-'slot-name'. (print (book-title book1)) (print (book-author book1)) (print (book-id book1))
;; The 'book-p' type predicate was also created. (print (book-p book1)))Output
Section titled “Output”"The Pragmatic Programmer""Andy Hunt & Dave Thomas"9780201616224TFeatures and Options of defstruct
Section titled “Features and Options of defstruct”defstruct is highly customizable. You can define default values for slots and control the generation of helper functions.
Example: Slots with Default Values
Section titled “Example: Slots with Default Values”(defstruct user (name "Anonymous") ; Default value for the 'name' slot (level 1) ; Default value for 'level' email)
;; Create a user, providing only the required 'email' slot.(let ((new-user (make-user :email "guest@example.com"))) (print (user-name new-user)) ; Prints the default value (print (user-level new-user)))
;; Create another user, overriding the defaults.(let ((admin-user (make-user :name "Admin" :level 99 :email "admin@example.com"))) (print (user-name admin-user)))Output
Section titled “Output”"Anonymous"1"Admin"Structure Inheritance with :include
Section titled “Structure Inheritance with :include”Structures support single inheritance using the :include option. The new structure inherits all the slots from the parent structure.
(defstruct person name age)
;; The 'student' structure includes 'person', inheriting its slots.(defstruct (student (:include person)) major gpa)
(let ((s1 (make-student :name "Jane Doe" :age 21 :major "Computer Science" :gpa 3.8))) ;; We can use accessors from the parent structure. (print (student-name s1)) (print (student-major s1)))Output
Section titled “Output”"Jane Doe""Computer Science"defstruct vs. CLOS defclass
Section titled “defstruct vs. CLOS defclass”Choosing between defstruct and defclass (from the Common Lisp Object System) is a common design decision:
- Use
defstructwhen: You need a simple, lightweight data container. Structures are often implemented more efficiently by Lisp systems and are perfect for performance-sensitive code or when you just need to bundle a few pieces of data together. - Use
defclasswhen: You need the full power of object-oriented programming. This includes multiple inheritance, method specialization (polymorphism), and dynamic redefinition of classes, which are features not available to structures.
Think of defstruct as being for “data objects” and defclass for “behavioral objects”.
Conclusion
Section titled “Conclusion”defstruct is a practical and essential tool in the Lisp programmer’s toolkit. It provides a simple, efficient, and clean way to define custom data types for aggregating information, striking a perfect balance between raw lists and the full-featured CLOS.