I am trying to learn Elisp and just found this line that I don't understand, in a package that I use to send code from buffer to a terminal:

 (let* ((region-active (region-active-p))

        ;; The region to be sent
        (bds   (isend--region-boundaries)) ; <<-- *** LINE OF INTEREST ***
        (begin (car bds))
        (end   (cdr bds))

What does that command do? isend--region-boundaries is a function defined elsewhere), but bds isn't. So what's bds here?

Maybe it's just coincidence, but I have found the same keyword used elsewhere.

  • 2
    It's a temporary, let-bound variable. Judging from the fact that it contains the result of a function called ...-boundaries, I'd say bds is an abbreviation for "boundaries". – Dan Jul 17 '16 at 14:07

I'm with Dan, but I'm posting here so the question can be marked as answered. Another thing to understand about the code you posted is that it uses let*, which imposes an ordering on the variable assignments so that the value of bds assigned in the 2nd line of the let is available for use in the 3rd and 4th lines of the let*.

In a normal (let ((..., the ordering of assignments is not guaranteed, so the values of begin and end might be set to nil if those lines are evaluated before the 2nd line that sets the value of bds.


Sorry that I was not clear in my writing. As Jean-Pierre points out, the doc string does indeed say that all variables (right hand side) are evalled before any symbols (the left hand side) are bound. But the doc string does not say anything about the order in which the variables are bound, which was my point above.

As I understand it, the implementation of a standard (let is under no obligation to bind the variables in top to bottom order, as a code writer might expect. The implementation may or may not do the binding in the "right" order.

Not that it matters what order is used to bind the variables. Since all right hand side VALUEFORMS are evalled before any of the left hand side variables are bound, the values that actually get assigned to the left side variables are cast in stone before the first left side variable gets bound. So binding them top to bottom or bottom to top or in some other order won't make any difference to the final values each left side variable receives.

In a standard (let, the value of the left hand side bds variable above on line 2 is undefined at the time the right hand bds sides of lines 3 and 4 are evalled. So they must eval to nil, I would think.

Finally, the whole point of introducing a different kind of let, the (let* version, is to provide a let that does have the obligation to eval and bind the successive variables in a (let* sequentially. So with a (let*, the code in the original posting will eval+bind the bds, begin, and end variables in proper sequential order, completing each line before starting the next line, thereby guaranteeing valid right-hand bds values for lines 3 and 4.

Hopefully this update adds more clarity. The (let* doc string says:

Each VALUEFORM can refer to the symbols already bound by this VARLIST.

  • Very good to know the note on ordering Kevin. Thanks! – Amelio Vazquez-Reina Jul 17 '16 at 14:44
  • 2
    let also guarantees ordering of assignments, it's just that later bindings don't see the variables bound by earlier ones (but they can see side effects of running the expressions). – npostavs Jul 17 '16 at 15:33
  • Agreed, an interesting nuance to point out about seeing the side effects. I learned something new again.. :-) – Kevin Jul 17 '16 at 15:46
  • 1
    So what @Kevin says in the last sentence is false. From let docstring : "All the VALUEFORMs are evalled before any symbols are bound". Please correct. – JeanPierre Jul 17 '16 at 17:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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