Generally in procedural/imperative languages, it's best practice to place variable declarations as close to usage as possible.

This seems a little hazy in lisp, considering more code is used if there are separate lets.

Given an example function using two lets:

(defun draw-box (new-image corners)
  (let ((h-len (- (alast (alast corners))
                  (alast (car corners))))
        (h-offset (alast (car corners))))
    (dotimes (i h-len)
      (setf (aref new-image (car (car corners)) (+ i h-offset) 0) 0)
      (setf (aref new-image (car (car corners)) (+ i h-offset) 1) 255)
      (setf (aref new-image (car (car corners)) (+ i h-offset) 2) 0)

      (setf (aref new-image (car (alast corners)) (+ i h-offset) 0) 0)
      (setf (aref new-image (car (alast corners)) (+ i h-offset) 1) 255)
      (setf (aref new-image (car (alast corners)) (+ i h-offset) 2) 0)))

  (let ((v-len (- (car (alast corners))
                  (car (car corners))))
        (v-offset (car (car corners))))
    (dotimes (i v-len)
      (setf (aref new-image (+ i v-offset) (alast (car corners)) 0) 0)
      (setf (aref new-image (+ i v-offset) (alast (car corners)) 1) 255)
      (setf (aref new-image (+ i v-offset) (alast (car corners)) 2) 0)

      (setf (aref new-image (+ i v-offset) (alast (alast corners)) 0) 0)
      (setf (aref new-image (+ i v-offset) (alast (alast corners)) 1) 255)
      (setf (aref new-image (+ i v-offset) (alast (alast corners)) 2) 0))))

Where I'm not going to use v-len and v-offset until halfway down the function, I'm hesitant to declare it at the top of the function just to use only a single let.

What is generally regarded as best practice when declaring variables in longer functions where one might only use a variable later on in the function?

  • Interesting question, but topics about how to write code should rather go to stackoverflow – Christophe Dec 6 at 8:44
  • 2
    I did initially start writing the question up on SO, but was warned that "best practice" questions would be closed as off-topic. – Joel Lord Dec 6 at 9:50
  • 2
    Ok ! Difficult to follow the sometimes contradictory editorial approches here and there.... – Christophe Dec 6 at 12:06
  • "Generally in procedural/imperative languages, it's best practice to place variable declarations as close to usage as possible.": This is not always the case: in Pascal you have to declare variables before the beginning of a block. If I remember correctly, C has the same rule, unless this has been changed in recent revisions of the language. I think the rationale behind this approach is that a block should never be too long anyway. – Giorgio Dec 6 at 19:13
up vote 6 down vote accepted

Your approach is correct: we bind (rather than declare, as in other languages) variables exactly where we need them. (In your case, however, you are using h-offset in the 1st half of your function, just without naming it).

The rationale is the same - code readability.

Note that you do not need to bind a single use variable, you can just write

(dotimes (i (- (alast ...) (alast ...)))
  ...)

Note also that you might want to make a few other changes (e.g., single call to setf and defining a separate function that modifies image).

Note also that you should not recompute things like (alast (alast corners)) in a loop (I surmise from the name that each alast has linear speed), so you should probably do something like this:

(defun draw-box (new-image corners)
  (let* ((corners-0 (car corners))
         (v-offset (car corners-0))
         (h-offset (alast corners-0))
         (corners-l (alast corners))
         (h-last (alast corners-l))
         (v-last (car corners-l)))
    (flet ((set-0-255-0 (x y)
             (setf (aref new-image x y 0) 0
                   (aref new-image x y 1) 255
                   (aref new-image x y 2) 0)))
      (loop for i = h-offset below h-last do
          (set-0-255-0 v-offset i)
          (set-0-255-0 v-last i))
      (loop for i = v-offset below v-last do
          (set-0-255-0 i h-offset)
          (set-0-255-0 i h-last)))))
  • Brilliant, thank you. With single-use functions like set-0-255-0 (assuming I only use it in that one function) would it be better to flet it inside draw-box? – Joel Lord Dec 6 at 16:56
  • 1
    Yes, if you are sure you will never need it, flet is quite appropriate. – sds Dec 6 at 16:58
  • it might also be helpful to declare the function to be inlined... – Rainer Joswig Dec 13 at 10:32
  • in the example it's probably 255 and not 2? Not that it matters much for the example... – Rainer Joswig Dec 13 at 10:34

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.