I certainly didn’t feel insulted. What I meant is that it was insulting for programmers in general, and that insult is not an argument. Thinking that programmers would be worst than I am or even as bad as I am and that it would be a valid reason to remove linked lists would be basing the decision upon cognitive bias. Whether programmers are able or not to make an educated decision about using linked lists is irrelevant. The only question is whether they are useful for some use cases or not.
Array-based lists are very error-prone too. I have seen many bugs due to the fact that these lists are not persistent. Programmers know that they have to make defensive copies when necessary. The problem is that people arguing against linked lists (note that I am talking about immutable persistent linked lists and not Java linked lists) generally “forget” this.
I have made a benchmark comparing (immutable persistent) linked lists, Kotlin mutable lists, and Kotlin’s non-modifiable lists. I have compared operations that are not well suited to linked lists as well as one which is: a scan of the list. A scan is like a fold but producing a list of all the intermediate results. Here are the results (in milliseconds):
Insertion of 100000 elements to the start of a linked list: 61
Insertion of 100000 elements to the start of a mutable list: 1411
Insertion of 100000 elements to the start of a non-modifiable list: 18
Insertion of 100000 elements to the end of a non-modifiable list: 9670
Insertion of 100000 elements to the end of a mutable list: 16
Retrieval of 100000 elements from the start of a linked list: 28
Retrieval of 100000 elements from the start of a mutable list: 22
Retrieval of 100000 elements from the start of a non-modifiable list: 3
Retrieval of 100000 elements from the end of a linked list: 25
Retrieval of 100000 elements from the end of a non-modifiable list: 3
Retrieval of 100000 elements from the end of a mutable list: 2
Reversing a 100000 elements linked list: 2
Reversing a 100000 elements mutable list: 4
Reversing a 100000 elements non-modifiable list: 7
Scanning a 100000 elements linked list: 19
Scanning a 100000 elements mutable list: 11
This seems to show that except for insertion, linked lists are not very performant.
The problem is that ther is a bug in the scan function:
fun <T> scan(list: MutableList<T>): MutableList<MutableList<T>> {
val result = mutableListOf<MutableList<T>>()
for (i in (0..list.size)) {
result.add(list.subList(0, i))
}
return result
}
With this implementation, any modification to the original list after the scan will be seen in the result of the scan, and any modification to the result of the scan will be seen in the original list. Once the bug is fixed (by making a copy of each sublist), there is a slight difference:
Scanning a 100000 elements linked list: 21
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Let’s try with a smaller list (20 000 elements):
Scanning a 20000 elements linked list: 7
Scanning a 20000 elements mutable list: 8136
As you can see, there are use cases for which array-based lists are dangerous and immutable persistent linked lists are much safer and much more performant.