Google Common Lisp Style Guide say Avoid modifying local variables, try rebinding instead
What does it mean? What does rebinding mean in that sentence?
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.
(let ((x (abs x))) ...)
would also work -- not so much the abs
function, but the fact that the same variable name can be used for the new variable. –
Proclus 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)))
© 2022 - 2024 — McMap. All rights reserved.
(let ((a 1)) (let ((a 2)) ...))
– Bluestockingloop
modifies local variables. In(loop for i below 10 ...)
, rebinding ofi
does not take place; a single instance ofi
is stepped, so "avoid modifying local variables" is tantamount to "avoidloop
". And thus, by "reductio ad religio" rule of inference, we prove this guideline wrong. – DonallLOOP
binds a new variable or changes the existing one. And I understand this as a general guideline, rather than a strict rule that must not be broken. – Sosthena