Optimised Code Patterns
This chapter documents all the automatic Lisp
code transformations, done by the Lisp Optimiser, during Lisp file
load-time.
The tables show the original Lisp code on left
side, and the optimised code on right side.
Additionally, some explanations on the reasons
and benefits, and also some insights to the BricsCAD Lisp engine
behaviour and special conditions.
All the effects of code pattern optimisations
can be verified with dedicated Lisp Benchmarks by
every developer.
1. empty arguments and local variables list
(defun func ( x y z / ) |
=> |
(defun func ( x y z ) |
(defun func ( / ) |
=> |
(defun func ( ) |
as the / character indicates
a list of local variables, the BricsCAD Lisp engine needs to parse
the local variables identifiers, because the internal structure of
the defun block depends both on arguments and local
variables; |
2. single statement inside (progn ...)
(progn (setq var 123) ) |
=> |
(setq var 123) |
the (progn ...) statement is not a lightweight operation, triggering some significant internal operations, in our Lisp engine (might be different in other AutoLISP implementations); in combination with a single expression the (progn ..:) does not make real sense, so eliminating this provides a better performance and reduced memory load |
3. comparison with 'nil'
(if (= var nil) ...) |
=> |
(if (not var) ...) |
(if (eq var nil) ...) |
=> |
(if (not var) ...) |
(if (equal var nil) ...) |
=> |
(if (not var) ...) |
(if (/= var nil) ...) |
=> |
(if (boundp var) ...) |
using the "=", "eq", "equal"
and "/=" functions always do a comparison "by value", so the "var"
variable is evaluated for its content, and depending on the type of
content (number, string, ename etc.) compared with the 'nil'
argument; |
4. unnecessary (progn ...)
(while (expr) (progn ...)) |
=> |
(while (expr) ...) |
(repeat (expr) (progn ...)) |
=> |
(repeat (expr) ...) |
(foreach item lst (progn ...)) |
=> |
(foreach item lst ...) |
the (progn ...) which encloses the entire code of "while", "repeat", "foreach" is not necessary at all - but causes significant overhead for our Lisp engine (see above); so eliminating that (progn ...) improves performance and reduces memory load |
5. COM property and method names as strings
(vlax-get-property object "property") |
=> |
(vlax-get-property object 'property) |
(vlax-put-property object "property" ...) |
=> |
(vlax-put-property object 'property ...) |
(vlax-invoke-method object "method" ...) |
=> |
(vlax-invoke-method object 'method ...) |
using symbol name instead of string name provides some internal advantages (less string copy operations, no uppercase conversion necessary) |
6. list member access by index
(nth 0 lst) ... (nth 9 lst) |
=> |
|
using the (nth) function is very common code - especially (nth 0 lst), (nth 1 lst) is widely used, though the (car lst), (cadr) etc. functions are more performant; the Optimiser uses the (vle-nth) function here, for indices 0...9. Especially when (nth 0 lst) etc. is used inside loops, the performance gain is surprisingly : reason is, that (vle-nth) function uses only 1 argument rather than 2, which reduces the amount of push/pop operations in Lisp stack. |
7. (cdr (assoc ...))
(cdr (assoc item lst)) |
=> |
(vle-cdrassoc item lst) |
the (cdr (assoc ...)) is one
of the most fundamental code patterns found in any Lisp dialect ...
but any modern Lisp dialect has a dedicated function
cassoc (or
similar) for this elementary operation; our Lisp engine
provides (vle-cdrassoc) for this
purpose, which provides significant performance gain, reduced
memory load and less GarbageCollections : |
8. (reverse (cdr (reverse ..)))
(reverse (cdr (reverse lst)) |
=> |
(vle-remove-last lst) |
another most fundamental
operation is to remove the last list item ... unfortunately,
AutoLISP does not provide a related function (as any modern Lisp
does) - developers have no other choice than to use this highly
ineffective code; |
9. (cdr (assoc dxf (entget ...)))
(cdr (assoc dxf (entget ename))) |
=> |
(vle-entget dxf ename) |
in the CAD environment, this
code pattern is also very basic and most often used; to improve
performance and efficiency here, the Lisp engine provides
the (vle-entget)
function : |
10. boolean usage of (tblsearch)
(not (tblsearch table
item)) |
=> |
(not (vle-tblsearch table item)) |
this code pattern is also
very basic and most often used to verify whether a particular table
item is present; to improve performance and efficiency here, the
Lisp engine provides the (vle-tblsearch) function
: |
11. boolean usage of (dictsearch)
(not (dictsearch dict
item)) |
=> |
(not (vle-dictsearch dict item)) |
this code pattern is also
very basic and most often used to verify whether a particular
dictionary item is present; to improve performance and efficiency
here, the Lisp engine provides the (vle-dictsearch)
function : |
12. boolean usage of (entget)
(not (entget
ename)) |
=> |
(not (vle-ename-valid ename)) |
this code pattern is also
very basic and most often used to verify whether a given entity is
valid and not erased; to improve performance and efficiency here,
the Lisp engine provides the (vle-ename-valid) function : |
The BricsCAD test system covers all these
cases to ensure proper operation.
© Bricsys NV. All rights reserved. |