4 ms·
> "Where necessary?" is almost always, because vectors almost always outperform linked lists based on cons cells. Let's see, I have here a Common Lisp compilin
by lispm 2y ago
> "Where necessary?" is almost always, because vectors almost always outperform linked lists based on cons cells.
Let's see, I have here a Common Lisp compiling to machine code, here non-optimized generic Lisp code:
I'm allocating n elements list/vector of vectors and reverse it p times. reversing allocates a new list/vector.
(defun test1 (n p)
(let ((v (make-array n)))
(map-into v
(lambda ()
(make-array 10 :initial-element 1000)))
(loop repeat p
do (setf v (reverse v)))
v))
(defun test2 (n p)
(let ((l (make-list n)))
(map-into l
(lambda ()
(make-array 10 :initial-element 1000)))
(loop repeat p
do (setf l (reverse l)))
l))
CL-USER 15 > (time (test1 10000 100))
Timing the evaluation of (TEST1 10000 100)
User time = 0.005
System time = 0.000
Elapsed time = 0.003
Allocation = 9088696 bytes
1 Page faults
GC time = 0.000
#(# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ...)
CL-USER 16 > (time (test2 10000 100))
Timing the evaluation of (TEST2 10000 100)
User time = 0.008
System time = 0.001
Elapsed time = 0.006
Allocation = 17113288 bytes
842 Page faults
GC time = 0.003
(# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ...)
The list or vector is 10000 elements long and 100 times reversed and the difference in runtime is tiny. The list version is only marginally slower, but allocates a lot more memory.
I can also construct cases, where the list is much faster. Adding a one element list/vector to the front:
CL-USER 22 > (time (test1 10000 100))
Timing the evaluation of (TEST1 10000 100)
User time = 0.016
System time = 0.000
Elapsed time = 0.012
Allocation = 9148776 bytes
0 Page faults
GC time = 0.000
#(A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A ...)
CL-USER 26 > (time (test2 10000 100))
Timing the evaluation of (TEST2 10000 100)
User time = 0.000
System time = 0.000
Elapsed time = 0.000
Allocation = 1042248 bytes
0 Page faults
GC time = 0.000
(A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A ...)
Here the runtime for lists is much faster, since it does not copy the complete list or -> lists share storage, consing to the front is cheap.
-> for many practical use cases for lists the total runtime and the runtime difference does not matter
Obviously there are also many case where a list would perform much worse, like accessing the last element of a list.
> Are you even capable of admitting that Lisp has serious faults
You seem to be keen to find "faults". Usually things are not black and white. There is no true and false, but engineering trade-offs. These tradeoffs can Lisp make the wrong choice for problems. Many of the trade-offs are also influenced by non-technical issues: like the amount of engineering time invested into a language implementation: see SUN/Oracles investment into Java.
- kerkeslager 2y agoSo, you did tests to show that linked lists are slower AND use more memory? Which we both already knew? Why? > I can also construct cases, where the list is much faster. Adding a one element list/vector to the front: Oh good, I'll keep that in mind for the next time I am forced to prepend a bunch of items to a list, which I expect to happen approximately 0 times before I die of old age. > > Are you even capable of admitting that Lisp has serious faults > You seem to be keen to find "faults". Usually things are not black and white. There is no true and false, but engineering trade-offs. These tradeoffs can Lisp make the wrong choice for problems. Many of the trade-offs are also influenced by non-technical issues: like the amount of engineering time invested into a language implementation: see SUN/Oracles investment into Java. So... what I'm hearing here is, that no, you aren't capable of admitting that Lisp has faults. I'm aware that tradeoffs exist. I'm also aware that faults exist. These two can both be true. It seems to me that being slower and using more memory and getting nothing in return isn't a tradeoff.
- lispm 2y ago> So, you did tests to show that linked lists are slower AND use more memory? Which we both already knew? Why? I showed you that it often does not matter much. > Oh good, I'll keep that in mind for the next time I am forced to prepend a bunch of items to a list, which I expect to happen approximately 0 times before I die of old age. It's not that uncommon, for example for a simple stack implementation. > So... what I'm hearing here is, that no, you aren't capable of admitting that Lisp has faults. With this discussion style you won't get very far. > It seems to me that being slower and using more memory and getting nothing in return isn't a tradeoff. Right, I think that's a useful task for you to actually think about: what do we get in return? Why does Haskell use linked lists? Why does INRIA's OCAML ( https://ocamlbook.org/lists-and-structural-recursion/ https://ocamlbook.org/lists-and-structural-recursion/ ) ? Why does Microsoft's F# ( https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/lists https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref... ) ? Why does Ericsson's Erlang ( https://www.erlang.org/doc/system/listhandling.html https://www.erlang.org/doc/system/listhandling.html ) ?
- 2y ago