Google Common Lisp Style Guide say Avoid modifying local variables, try rebinding instead
What does it mean? What does rebinding mean in that sentence?
It means that you should create new variables instead of changing the value of old ones. For example, let's take the following code:
(defun foo (x)
(when (minusp x)
(setq x (- x)))
do something with x)
Instead, one should create a new binding and use that one instead:
(defun foo (x)
(let ((xabs (if (minusp x)
(- x)
x)))
do something with xabs)
The reason for this is that you will always know what a variable contains, since it will never change. If you want the new value, simply use the variable that holds that new value.
Now you might ask why this is so important? Well, some people have a stronger preference for this than others. Especially people who prefer to emphasise the functional aspect of Lisp will advocate this style. However, regardless of preference, it can be very useful to always be able to rely on the fact that variables doesn't change. Here's an example where this can be important:
(defun foo (x)
(let ((function #'(lambda () (format t "the value of x is ~a~%" x))))
(when (minusp x)
(setq x (- x)))
(other-function x)
function))
Then, the return value of FOO
is a function that when called with print the value of x
. But, the value will be that of x
later in the function, the absolute value. This can be very surprising if the function is large and complicated.
I don't know Common Lisp well enough to answer with how to do this in Common Lisp, so I'm using Scheme for my example below. Suppose you're writing a function to return the factorial of a number. Here's a "modify local variables" approach to that function (you'll have to define your own while
macro, but it's not hard):
(define (factorial n)
(define result 1)
(while (> n 0)
(set! result (* result n))
(set! n (- n 1)))
result)
Here's a "rebind local variables" approach to that function:
(define (factorial n)
(let loop ((n n)
(result 1))
(if (zero? n)
result
(loop (- n 1) (* result n)))))
In this case, loop
is called with new values to rebind with each time. The same function can be written using the do
macro (which, by the way, also uses rebinding, not modifying, at least in Scheme):
(define (factorial n)
(do ((n n (- n 1))
(result 1 (* result n)))
((zero? n) result)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With