Category Archives: Uncategorized

The less-familiar parts of Lisp for beginners — deposit-field

Now we move on to deposit-field.  A cursory introduction to Lisp is unlikely to have discussed this function.  To begin, I’d suggest that you review the earlier article on byte.  The deposit-field function is used to remove a bitfield from one integer, SRC, and insert it into another integer, DST, returning the result.  How is this different from dpb, whose effects were shown in that article on byte?  In dpb, the byte specifier acts only to window DST.  That is, if the byte specifier is 5 bits wide, then the lowest 5 bits of SRC are used, regardless of the position of the byte specifier.  In deposit-field, SRC and DST are both windowed by the byte specifier, so it is possible to insert bits other than the least-significant bits of SRC.

This sort of bitfield manipulation is not used very frequently.  It’s essential when writing code to certain binary protocols, very useful for device drivers, network stacks, and things like that, but less commonly used in other applications.

The less-familiar parts of Lisp for beginners — delete-package

Our next obscure Lisp command for newcomers arriving from C++ is delete-package.  To begin, I’ll discuss what a package behaves like from the perspective of C++.

A package is a bit like a C++ namespace, but with a few extra twists.  In C++, a namespace is essentially a name-mangling tool.  It allows the programmer to create symbols without worrying too much about symbol name collisions.  In Lisp, a package has this quality, but also other properties.  First of all, a Lisp package is a real obect in the language, not simply a compiler directive for symbol naming.  The package is, very broadly, a symbol container.  Secondly, packages can inherit from other packages, and can therefore inherit symbols or override them as necessary.  Don’t confuse a package with a class, though, as you can define many classes or no classes in a package, and there isn’t an equivalent to polymorphism in the syntax of package symbol resolution, the way there is with class hierarchies and generic functions.

So, what does delete-package do?  Well, perhaps unsurprisingly, it deletes the package.  The result is that the classes and functions defined in the package are no longer visible in the Lisp environment.  Once again, the need for this is due to the fact that Lisp programs run in a Lisp environment, and not as self-contained things that are compiled and then executed.

For the newcomer, when might you need delete-package?  Most obviously, during development.  If you’re working in a package, and you’ve defined some generic functions, only to decide later that you need to change the interface of a generic function and the methods that implement it, your Lisp instance will complain when  you try to re-load the package, because redefining the generic function will bring it into conflict with the implemented methods.  By calling delete-package before reloading the modified file, you delete the changes that the package made to the Lisp system, and so can safely load the file.  Other cases where you might need to delete the package before loading it include when you’ve got a defconstant on a list (see the earlier discussion there), or when you’ve used defvar in the package.  Really, any time when the state of the package might modify the effect of loading the package again.

The less-familiar parts of Lisp for beginners — deftype

Moving onwards, the casual Lisp programmer arriving from C++ might not have encountered deftype in his or her reading.  There’s a fine description and example of the macro in the CLHS.  This macro allows the programmer to define a new type specifier.

So, why might the programmer want to create new type specifiers?  Most commonly, programmers either want to use them along with declare and the to provide compiler hints, helping the optimizer to know what underlying types are being used.  The programmer-defined type specifier is somewhat similar to a C++ typedef, by defining your own type specifier you can easily alter code when you have to change the underlying type, without having to search through your code for occurrences of the type.

New type specifiers also might be useful in typecase statements:
 

(defun equidimensional (a)
  (or (< (array-rank a) 2)
      (apply #'= (array-dimensions a))))

(defun all-ints (a)
  (let ((len (array-total-size a)))
    (dotimes (i len)
      (unless (integerp (row-major-aref a i))
        (return-from all-ints nil)))
    t))

(deftype square-matrix (&optional type size)
  `(and (array ,type (,size ,size))
        (satisfies equidimensional)))

(deftype integer-square-matrix (&optional size)
  `(and (square-matrix integer ,size)
        (satisfies all-ints)))

(defun demonstrate ()
  (let ((objects (list :ABC
                       (make-array '(2 3))
                       (make-array '(2 2) :initial-element 1)
                       (make-array '(2 2) :initial-element 1.1))))
    (dolist (obj objects)
      (format t "~S~26T" obj)
      (typecase obj
        (integer-square-matrix
         (format t "is an integer square matrix"))
        (square-matrix
         (format t "is a square matrix"))
        (array
         (format t "is a non-square matrix"))
        (t
         (format t "is a non-matrix")))
      (format t "~%"))))

Producing output:
 
CL-USER> (demonstrate)
:ABC                      is a non-matrix
#2A((0 0 0) (0 0 0))      is a non-square matrix
#2A((1 1) (1 1))          is an integer square matrix
#2A((1.1 1.1) (1.1 1.1))  is a square matrix
NIL

The less-familiar parts of Lisp for beginners — defsetf

We talked about define-setf-expander.  That’s a fairly powerful macro that allows setf to operate on things that aren’t what the C++ programmer would think of as an “lvalue”.  There is also defsetf.  Less powerful, but simpler to use, so it’s generally preferred when its use is possible.

There are two forms of defsetf, a short form for very simple cases, and a long form for slightly longer cases.

If you have an access function that takes a certain number of arguments, and a setting form that takes exactly one more argument, the new value to substitute, and if that second function returns this new value, then you can use the short form.  Here’s an example:
 

(defparameter *num-counters* 10)
(defparameter *counter-array* (make-array *num-counters*
                                          :initial-element 0))

(defun get-next-counter (index)
  (assert (<= 0 index (1- *num-counters*)))
  (incf (aref *counter-array* index)))

(defun set-counter-value (index val)
  (assert (<= 0 index (1- *num-counters*)))
  (assert (integerp val))
  (setf (aref *counter-array* index) (1- val))
  val)

(defsetf get-next-counter set-counter-value)

(defun demonstrate ()
  (format t "Next counter 0: ~D~%" (get-next-counter 0))
  (format t "Next counter 0: ~D~%" (get-next-counter 0))
  (format t "Next counter 0: ~D~%" (get-next-counter 0))
  (format t "Next counter 1: ~D~%" (get-next-counter 1))
  (format t "Setting next counter 0 value to 100~%")
  (setf (get-next-counter 0) 100)
  (format t "Next counter 0: ~D~%" (get-next-counter 0))
  (format t "Next counter 1: ~D~%" (get-next-counter 1)))

With output:
 
CL-USER> (demonstrate)
Next counter 0: 1
Next counter 0: 2
Next counter 0: 3
Next counter 1: 1
Setting next counter 0 value to 100
Next counter 0: 100
Next counter 1: 2
NIL

When the arguments list to the function you’re working with is a bit more complicated, such as if it has optional arguments, the long form may still be suitable:
 

(defparameter *test-set* (list :A :B :C :C :D :C :A :B :A :C))

(defun member-in-test-set (sym &key (skip 0))
  (let ((rv (member sym *test-set*)))
    (do ()
        ((or (not rv) (= skip 0)) rv)
      (setf rv (member sym (cdr rv)))
      (decf skip))))

(defun set-member-in-test-set (sym new-sym &key (skip 0))
  (let ((rv (member sym *test-set*)))
    (do ()
        ((or (not rv) (= skip 0)))
      (setf rv (member sym (cdr rv)))
      (decf skip))
    (when rv
       (rplaca rv new-sym))
    new-sym))

(defsetf member-in-test-set (sym &key (skip 0)) (new-sym)
    `(set-member-in-test-set ,sym ,new-sym :skip ,skip))

(defun demonstrate ()
  (format t "Test set is: ~S~%" *test-set*)
  (format t "Setting the second occurence of :A to :Y~%")
  (setf (member-in-test-set :A :skip 1) :Y)
  (format t "Test set is: ~S~%" *test-set*))

Giving output:
 
CL-USER> (demonstrate)
Test set is: (:A :B :C :C :D :C :A :B :A :C)
Setting the second occurence of :A to :Y
Test set is: (:A :B :C :C :D :C :Y :B :A :C)
NIL

As I mentioned in the article about define-setf-expander, you might initially ask why bother writing a setf expander when the programmer can simply call the appropriate modification functions directly.  The most likely reason you’d use an expander instead is that you have existing macros that make use of setf for some work, and you’d like to use it to setf one of its passed arguments, but that argument doesn’t look like an lvalue.  Rather than writing runtime checks against type and changing the macro to account for all such cases, you can simplify your code by writing an setf expander and hiding the special-case code underneath it.

The less-familiar parts of Lisp for beginners — define-symbol-macro

Another feature of Lisp that the newcomer might not have encountered is define-symbol-macro.  Think of this as something very close to a C/C++ macro.  It is a way to define a symbol that will be expanded at compile time.  Where the more familiar Lisp macros have a function-like syntax, this creates a macro with a symbol-like syntax, so it is called without surrounding parentheses.

Here’s a short bit of code to demonstrate this:
 

(define-symbol-macro now (get-time-of-day))
(define-symbol-macro first-fred (car fred))

(defun demonstrate ()
  (format t "The value of symbol 'now' is: ~A~%" now)
  (let ((fred (list 1 2 3 4 5)))
    (format t "The value of symbol 'first-fred' is ~A~%" 
            first-fred)
    (let ((fred (list :A :B :C :D :E)))
      (format t "The value of symbol 'first-fred' is ~A~%" 
              first-fred))))

With output:
 
CL-USER> (demonstrate)
The value of symbol 'now' is: 1388450944
The value of symbol 'first-fred' is 1
The value of symbol 'first-fred' is A
NIL
CL-USER> (macroexpand 'now)
(GET-TIME-OF-DAY)
T
CL-USER> (macroexpand 'first-fred)
(CAR FRED)
T