Does elisp calculate values of local variables at declaration or when calling them?

Say i want to find out what headlines in buffer are lvl2, and do stuff to them:

(defun map-org-heads ()
  (org-element-map (org-element-parse-buffer 'headline) 'headline 'do-stuff))

Would this:

(defun do-stuff (element)
  (let ((lvl (org-element-property :level element)))
    (if (eq lvl 2)

Have a better performance than this:

(defun do-stuff (element)
  (let ((begin (org-element-property :begin element))
        (end (org-element-property :end element))
        (lvl (org-element-property :level element))
        (title (org-element-property :title element)))
    (if (eq lvl 2)
        (........... do stuff))))

I have quite a big org-file with lots of headlines, so every bit of performance matters.

  • 1
    This question is a little unclear; please clarify it. You can also test the performance of two different functions by profiling you code to see which one is faster. – Dan Nov 29 '18 at 16:07
  • The question is unclear, in part because you don't show enough in the two contrasting examples. In the second example you don't show any use of the other local variables, and we can't guess what the correspondence is, if any, between (...... do stuff) and (call-func-to-do-stuff). – Drew Nov 29 '18 at 17:36
  • Are you asking whether elisp has lazy evaluation? It doesn't. – user12563 Nov 29 '18 at 18:22
  • org-element-property is a two-liner that relies upon either get-text-property or plist-get depending upon whether ELEMENT is a stringp. Neither of these would consume time with a standard org-mode. It is the combing through of large org-mode files and examining that information for multiple headings that causes a noticeable time consumption. I personally like to search backward for headings (that interest me) from the bottom of the file to the top because point is at the beginning of a heading at each stop (assuming re-search-backward is being used). – lawlist Nov 29 '18 at 20:02
  • Here is a link to a measure-time macro in case you want to wrap it around something that interests you: stackoverflow.com/questions/23622296/… – lawlist Nov 29 '18 at 20:05

From the elisp manual for let:

This special form sets up local bindings for a certain set of variables, as specified by BINDINGS, and then evaluates all of the FORMS in textual order.
All of the VALUE-FORMs in BINDINGS are evaluated in the order they appear and before binding any of the symbols to them.

Which means that any computations required to define the local variables are done first, then the results are bound to the symbols, and finally the body is evaluated.

Here's a simple(-minded) example:

(defun return-tmp ()

(setq tmp 1)

(defun test-let ()
  (let ((tmp1 (return-tmp))) ;; create tmp1, give it the value of tmp
    (setq tmp 2)             ;; change the value of tmp
    tmp1))                   ;; return the value stored in tmp1

tmp          ;; => 1, the initial value of tmp
(test-let)   ;; => 1, the value of tmp when tmp1 was defined
tmp          ;; => 2, the value of tmp when test-let returned
| improve this answer | |

Does elisp calculate values of local variables at declaration or when calling them?

At declaration, thus the value is computed even if you don't use the variable at all.

Would this: ... Have a better performance than this: ...

Yes, since the former sometimes avoids unnecessary computation. However, don't worry about performance when you are not sure it is worth. If it is slow, you will know. In this case, org-element-property is very fast so you probably won't notice the performance difference between these two.

| improve this answer | |

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.