From Google Common Lisp Style Guide: "Avoid modifying local variables, try rebinding instead" meaning?
Asked Answered
G

2

5

Google Common Lisp Style Guide say Avoid modifying local variables, try rebinding instead

What does it mean? What does rebinding mean in that sentence?

Gentianella answered 18/6, 2013 at 8:7 Comment(3)
Rebinding, most likely, as in masking the previous name with the new one, e.g., (let ((a 1)) (let ((a 2)) ...))Bluestocking
This is a dumb guideline. Go a head and modify local variables all you want. Note that loop modifies local variables. In (loop for i below 10 ...), rebinding of i does not take place; a single instance of i is stepped, so "avoid modifying local variables" is tantamount to "avoid loop". And thus, by "reductio ad religio" rule of inference, we prove this guideline wrong.Donall
As you probably know, the Common Lisp standard does not specify whether or not LOOP 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
V
9

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.

Vane answered 18/6, 2013 at 11:18 Comment(3)
+1. It's also interesting to note that (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
The closure referring to a modified value reminds me of how in JavaScript, using a for-loop to iterate over an array of buttons and attaching onclick handlers which refer to an iteration index is a bad ideaGentianella
@LeCurious The closure-over-iteration-variable issue comes up in Common Lisp as well, particularly with the loop macro. For instance, see unexpected behavior with loop macro and closures, which demonstrates this exact behavior.Polymerization
T
4

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)))
Thyself answered 18/6, 2013 at 11:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.