5. Common programming pitfalls

5.1. The read-eval-print loop is just sitting there after I've typed in my form. What's happening?
5.2. I want an array of foos, but (make-array 10 :initial-element (make-foo)) causes strange bugs. Why?
5.3. Why does (read-from-string "foobar" :start 3) return FOOBAR instead of BAR?
5.4. Why can't I apply #'AND or #'OR?
5.5. Why are my structure contents wrong?
5.6. Why isn't there a DEEP-COPY function in the language?
5.1.

The read-eval-print loop is just sitting there after I've typed in my form. What's happening?

One possible explanation for this behaviour is that you have typed in a program that causes an infinite loop; for instance (loop).

However, the fact that you are surprised by this behaviour suggests that this isn't the case; in which case a far more likely explanation is that your form is not quite complete. You may have typed a doublequote, vertical bar, "#|" comment beginning, or left parenthesis that you never matched with another doublequote, vertical bar, "|#", or right parenthesis, respectively. Try typing a few right parentheses followed by Return.

5.2.

I want an array of foos, but

      (make-array 10 :initial-element (make-foo))
      

causes strange bugs. Why?

Well, the array created above contains 10 pointers to the same foo, which will indeed cause strange bugs. The correct way to initialize your array is probably

        (map-into (make-array 10) #'make-foo)
      
5.3.

Why does (read-from-string "foobar" :start 3) return FOOBAR instead of BAR?

READ-FROM-STRING is one of the rare functions that takes both &OPTIONAL and &KEY arguments:


        READ-FROM-STRING string &OPTIONAL eof-error-p eof-value &KEY :start :end :preserve-whitespace
      

When a function takes both types of arguments, all the optional arguments must be specified explicitly before any of the keyword arguments may be specified. In the example above, :START becomes the value of the optional EOF-ERROR-P parameter and 3 is the value of the optional EOF-VALUE parameter.

To get the desired result, you should use (read-from-string "foobar" t nil :start 3). If you need to understand and use the optional arguments, please refer to CLTL2 under READ-FROM-STRING, otherwise, this will behave as desired for most purposes.

The other functions with this peculiarity in the COMMON-LISP package are PARSE-NAMESTRING, WRITE-LINE and WRITE-STRING.

5.4.

Why can't I apply #'AND or #'OR?

Here's the simple, but not necessarily satisfying, answer: AND and OR are macros, not functions; APPLY and FUNCALL can only be used to invoke functions, not macros and special operators.

OK, so what's the real reason? The reason that AND and OR are macros rather than functions is because they implement control structure in addition to computing a boolean value. They evaluate their subforms sequentially from left/top to right/bottom, and stop evaluating subforms as soon as the result can be determined (in the case of AND, as soon as a subform returns NIL; in the case of OR, as soon as one returns non-NIL); this is referred to as "short circuiting" in computer language parlance. APPLY and FUNCALL, however, are ordinary functions; therefore, their arguments are evaluated automatically, before they are called. Thus, were APPLY able to be used with #'AND, the short-circuiting would be defeated.

Perhaps you don't really care about the short-circuiting, and simply want the functional, boolean interpretation. While this may be a reasonable interpretation of trying to apply AND or OR, it doesn't generalize to other macros well, so there's no obvious way to have the Lisp system "do the right thing" when trying to apply macros. The only function associated with a macro is its expander function; this function accepts and returns and form, so it cannot be used to compute the value.

The Common Lisp functions EVERY and SOME can be used to get the functionality you intend when trying to apply #'AND and #'OR. For instance, the erroneous form: (apply #'and *list*) can be translated to the correct form: (every #'identity *list*).

5.5.

Why are my structure contents wrong?

Most probably, one of your structure slots is called `p'. The accessor for this slot will clash with the default predicate that defstruct defines for your structure; so if you have (defstruct bar (p 1) (q 2)), you could easily see (make-bar) return #S(bar :p t :q 2).

To avoid this, use the :predicate defstruct option to eliminate or rename the predicate function, or else use a different slot name.

5.6.

Why isn't there a DEEP-COPY function in the language?

Copying an arbitrary structure or object needs context to determine what is the correct copy.

For instance, consider a queue data structure, most easily implemented as a pair of pointers, one pointing to the head of the queue and another to the tail

See Kent Pitman's article on the nature of equality.