Code Structure

Parent Previous Next

Code Structure


When reviewing client Lisp code, we encountered and collected a number of code patterns, which are not only ineffective - but even rather bad in the context of performance and memory usage.
Such cases are collected here for analysis and documentation - and how to avoid bottlenecks.


1. local DEFUN blocks :


(defun mainFunc ( / localFunc )
   ;; some code
   (defun localFunc ()
       ;; some local code
   )
   ;; some code
)


If the "mainFunc" function is often called, the local definition of "localFunc" becomes a performance bottleneck.
Other than with compiled languages, the Lisp interpreter always re-evaluates the local defun block, and re-creates that local function, while the local function does not change at runtime, of course.

It also does not make a difference whether "localFunc" is declared as a local symbol (in "mainFunc") or not - the only difference for a locally declared function is, that the function body is automatically set as NIL when the code flow leaves "mainFunc";
otherwise, when not declared locally, the "localFunc" function becomes a global one (at global scope) and is redefined as global function when "mainFunc" is re-entered again.

So in any case, the repeated evaluation of (defun localFunc ...) code block creates unnecessary performance overhead, and additionally fills the Lisp memory, triggering more GarbageCollections.

Suggestion :
even as possible from technical point, it does not make real sense - except, when several main functions all declare + use a same-named local function. Therefore, it is best to avoid such code designs for better performance and less memory load.


2. (while) loop iterating over a list :


(while (setq item (car lst))
   (setq lst (cdr lst))
   ;; some code
)


better approach :

(foreach item lst
   ;; some code
)


The (foreach) loop saves 4 operations :
       (setq item (car lst)) - 2 operations : (car) and (setq)
       (setq lst (cdr lst))    - 2 operations : (cdr) and (setq)
so it reduces execution time by 4 operations for each loop cycle, and many temporary Lisp objects, as "item" and "lst" variables are reassigned new values with each cycle;
such temporary objects fill the Lisp memory and trigger earlier GarbageCollections, which in turn also reduce the overall performance.




©  Menhirs NV. All rights reserved.