3 ms·
The author makes the claim that structures and CLOS classes are not widely used. The opposite is true. CL-USER 202 > (gp:make-graphics-state :thickness 2 :da
by lispm 9y ago
The author makes the claim that structures and CLOS classes are not widely used. The opposite is true.
CL-USER 202 > (gp:make-graphics-state :thickness 2 :dashed t)
#S(GRAPHICS-PORTS:GRAPHICS-STATE :TRANSFORM (1 0 0 1 0 0) ...)
Oh, wow, a graphics state for drawing is not a list, but a structure object.
CL-USER 204 > (make-random-state)
#S(RANDOM-STATE :J 44 :K 20 :SEED ...)
Oh, wow, a random state is not a list, but a structure object.
CL-USER 205 > (pathname "/foo/bar/baz.lisp")
#P"/foo/bar/baz.lisp"
CL-USER 206 > (describe *)
#P"/foo/bar/baz.lisp" is a PATHNAME
HOST NIL
DEVICE NIL
DIRECTORY (:ABSOLUTE "foo" "bar")
NAME "baz"
TYPE "lisp"
VERSION NIL
Oh, wow, a pathname is not a list or string, but a pathname object.
The Lisp I'm using has literally thousands of structure classes and CLOS classes defined. A Lisp Machine of the mid 80s had around 6000 classes defined.
CL-USER 158 > (defclass vec3d ()
((x :initarg :x) (y :initarg :y) (z :initarg :z)))
#<STANDARD-CLASS VEC3D 40201F4F8B>
CL-USER 159 > (with-slots (x y z) (make-instance 'vec3d :x 3 :y 4 :z -3)
(format t "(~S,~S,~S)" x y z))
(3,4,-3)
The only thing to understand is that Lisp code is usually not optimized for shortest code on the token level.
Though more compact versions of the DEFCLASS macro are being used sometimes. If an application needs a shorter notation, the programmer can always use macros and read-macros to introduce that.
The advantage of CLOS instances and structures over hashtables/vectors/lists is that they carry their class and that they use features like inheritance and method dispatch. The usual OO stuff.
Structures can have by-order-arguments and already print themselves readable:
CL-USER 162 > (defstruct (svec3d (:constructor svec3d (x y z))) x y z)
SVEC3D
CL-USER 163 > (svec3d 1 2 3)
#S(SVEC3D :X 1 :Y 2 :Z 3)
A structure can also have accessor functions without the structure name prefix:
CL-USER 168 > (defstruct (svec3d
(:constructor svec3d (x y z))
(:conc-name))
x y z)
SVEC3D
CL-USER 169 > (let ((p (svec3d 1 2 3)))
(format t "(~S,~S,~S)" (x p) (y p) (z p)))
(1,2,3)
NIL
One can also provide multiple constructors and embed literal objects in code:
CL-USER 187 > (defstruct (svec3d (:constructor svec3d (x y z))
(:constructor make-svec3d)
(:conc-name)) x y z)
SVEC3D
CL-USER 188 > #S(SVEC3D :X 1 :Y 2 :Z 3)
#S(SVEC3D :X 1 :Y 2 :Z 3)
CL-USER 189 > (let ((p #S(SVEC3D :X 1 :Y 2 :Z 3)))
(format t "(~S,~S,~S)" (x p) (y p) (z p)))
(1,2,3)
NIL
Some implemetations also support the use of WITH-SLOTS with structures:
CL-USER 190 > (with-slots (x y z) #S(SVEC3D :X 1 :Y 2 :Z 3)
(format t "(~S,~S,~S)" x y z))
(1,2,3)
NIL
The tradition of Lisp usually is to give the programmer the choice of representation: adhoc lists/vectors/multiple values or structures (efficient records) or CLOS classes (flexible objects) or any kind of user defined stuff...
For any larger code and CLOS classes are usually the default choice for tuple data structures which don't need the last bit of efficiency.
- flavio81 9y agoExcellent post. Sometimes i get to think that CL is fully object oriented beneath the surface.