Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

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

like image 214
Le Curious Avatar asked Jun 18 '13 08:06

Le Curious


2 Answers

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.

like image 56
Elias Mårtenson Avatar answered Oct 28 '22 02:10

Elias Mårtenson


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)))
like image 24
Chris Jester-Young Avatar answered Oct 28 '22 00:10

Chris Jester-Young