I definitely like those too. They save a lot of programming
... but when used in the correct places they don't necessarily make for "inefficient" programming. In Lisp they're actually quite efficient in themselves, it's when you try them in something like C# (which has to load the entire Linq libraries simply to use such constructs) when the overhead comes to play.
Actually even in those days-gone-by these functions were used in extremely efficient programming. Even to the point where it became an art-form
. It's usually a case of the optimization is handled by the compiler / interpreter in such a way as to make for more efficient running code.
E.g. using a while loop with a counter variable extracting from a list of strings and running strcat to concatenate them all together would not only be a lot of typing, but would use at least twice the amount of RAM and probably be slower than simply using apply:
;; Iterative strcat of list
(defun strcat-list-1 (lst / str n)
(setq n (length lst) str "")
(while (> (setq n (1- n)) -1)
(setq str (strcat (nth n lst) str))
)
str
)
;; Iterative strcat of list - using foreach
(defun strcat-list-1a (lst / str)
(setq str "")
(foreach item lst
(setq str (strcat str item))
)
str
)
;; Recursive strcat of list
(defun strcat-list-2 (lst / )
(if (cdr lst)
(strcat (car lst) (strcat-list-2 (cdr lst)))
(car lst)
)
)
;; Minimal version using apply
(defun strcat-list-3 (lst / )
(apply 'strcat lst)
)
And the test:
_$ (setq lst '("This" " " "is" " " "a" " " "test."))
("This" " " "is" " " "a" " " "test.")
_$ (benchmark '((strcat-list-1 lst) (strcat-list-1a lst) (strcat-list-2 lst) (strcat-list-3 lst)))
Benchmarking ..................Elapsed milliseconds / relative speed for 32768 iteration(s):
(STRCAT-LIST-3 LST)......1141 / 1.47 <fastest>
(STRCAT-LIST-2 LST)......1313 / 1.27
(STRCAT-LIST-1A LST).....1390 / 1.20
(STRCAT-LIST-1 LST)......1672 / 1.00 <slowest>
So you can see the recursive & foreach are close. But the while is slow as molasses. The apply is a lot faster in comparison.