News for hackers. Stuff that matters.
Re:In Defense of Linked Lists by andirk on Friday November 04, 2022 @06:23PM (#33474749)
Understanding, and even sympathizing, with the machine's toil re: vectors vs manual linked list can separate a good engineer from a great one. We learn linked lists, assembly, and even machine code in Computer Science majors so that we know what's happening under the hood and can more easily surmise the runtime effects.
Re:In Defense of Linked Lists by kibwen on Friday November 04, 2022 @06:32PM (#33474876)
All of these are indeed important, and will eventually (one hopes) result in the student realizing that linked lists are to be avoided because of their poor mechanical sympathy resulting from their awful cache locality.

Valid uses for a linked list are extremely niche. Yes, you can name some, and I can name several valid uses for bloom filters.

Re:In Defense of Linked Lists by throwawaymaths on Friday November 04, 2022 @06:49PM (#33475083)
Wait why do linked lists have bad cache locality? It depends on how your heap is set up. For example, you could have an allocator that gives relatively good locality by having high granularity and only bailing out if say your LL gets super long (so if your lists are usually short, they could have awesome locality)
Re:In Defense of Linked Lists by duskwuff on Friday November 04, 2022 @07:11PM (#33475370)
That only works if you allocate lists all at once and never modify them.

If there are any other allocations taking place at the same time -- say, allocations from other threads, or for other data you had to create while building the list, that locality is shot. Same goes if you insert more elements to the list later, or if you perform an operation which changes its order (like sorting it).

Re:In Defense of Linked Lists by wtetzner on Saturday November 05, 2022 @12:23AM (#33477945)
> That only works if you allocate lists all at once and never modify them.

You can reorder and modify the contents of the list without losing locality.

Re:In Defense of Linked Lists by duskwuff on Saturday November 05, 2022 @01:09AM (#33478168)
I mean, if you modify the contents of the list nodes in place, sure. But at that point, you're just doing an array with extra steps.

Changing any of the pointers, however, will make memory prefetch much less efficient. CPUs like linear memory access patterns; they're easy to predict. Chasing pointers is much less predictable, even if the pointers are all to the same region of memory.

Re:In Defense of Linked Lists by wtetzner on Saturday November 05, 2022 @09:39AM (#33481359)
It might still be cheaper than copying the values if they’re large.
Re:In Defense of Linked Lists by cerved on Friday November 04, 2022 @07:24PM (#33475534)
That doesn't seem to make much sense to me. LL are useful in cases where you deal with changing lists, where you'd be forced to allocate and deallocate memory often. If you know before hand the exact or approximate size of the list and it's contents you can store that continuously in memory with greater cache locality because you're not storing pointers in addition to data. Seems to me the use case of LL is perhaps as ill suited for cache locality as the structure itself
Re:In Defense of Linked Lists by wtetzner on Saturday November 05, 2022 @12:24AM (#33477948)
They’re also useful when you want to cheaply reorder nodes without copying the elements.
Re:In Defense of Linked Lists by cerved on Saturday November 05, 2022 @06:45PM (#33486731)
True. You could implement that using an array of structs where each struct contains indexes of the array to link other structures. instead of memory pointers, since they are 8 bytes in 64-bit applications. This way you get the nice properties of both linked lists and continuously allocated arrays
Re:In Defense of Linked Lists by AstralStorm on Friday November 04, 2022 @07:11PM (#33475367)
If you are in that place, you're probably using a linked list over small statically allocated memory, but you still need random ordering and fast remove or reorder.
Re:In Defense of Linked Lists by CalChris on Saturday November 05, 2022 @12:08AM (#33477848)
If your list is short then you won't have a problem. But if your list is long then traversing it can be a major problem.

For example, if your list item is page aligned like the task_struct in the Linux kernel, rescheduling the next process could traverse the process list. The process list links will be at the same page offset and associate with a restricted set of the L1/L2/L3 caches lines and thrash from memory. Worse, the TLB will thrash as well. This was actually the case for Linux until about 2000.

https://www.usenix.org/legacy/publications/library/proceedin...

Re:In Defense of Linked Lists by mst on Friday November 04, 2022 @07:14PM (#33475398)
Re:In Defense of Linked Lists by atemerev on Saturday November 05, 2022 @07:45AM (#33480548)
An order book in electronic trading.

It is not too large (a few thousand of entries usually), but it needs to be accessed and modified extremely fast. There can be insertions and deletions anywhere, but it is strongly biased towards front. It is ordered by price, either ascending or descending.

Various “ordered queue” implementations are usually a poor fit, as there are many insertions and deletions in the middle, and they need to avoid any additional latency. The same goes to vectors. Red-black trees etc. are too complex (and slow) for such a small size.

So we start with a humble linked list, and optimize it (unrolled, skip search etc). But we respect linked lists, they work.

Re:In Defense of Linked Lists by BeetleB on Friday November 04, 2022 @08:01PM (#33475923)
> Understanding, and even sympathizing, with the machine's toil re: vectors vs manual linked list can separate a good engineer from a great one.

I think your parent's point is that if you're a C++ programmer, recognizing that vectors outperform other data structures for most use cases is what separates a good engineer from a great one. Often even for things that require lookup (i.e. vector outperforming a set).

During code reviews, a senior C++ programmer in my company (formerly sat in the C++ standards committee) would always demand benchmarks from the developer if they used anything else. In most cases, using representative real world data, they discovered that vectors outperformed even when the theoretical complexity of the other data structure was better.

A great engineer knows the limitation of theory.

Of course, my comment is only regarding C++. No guarantees that vectors are great in other languages.

Re:In Defense of Linked Lists by asveikau on Friday November 04, 2022 @08:21PM (#33476124)
> [V]ectors outperform other data structures ... even for things that require lookup (i.e. vector outperforming a set)

This is something I've heard before (not often benchmarked) and it makes intuitive sense, and sometimes I've also told it to myself in order to not feel bad for writing O(n) where n is always small.

But somehow, reading this snippet, I'm reminded that the vector does not maintain the semantic reminder that it's used in a key/value use case. So it has me thinking there should be a map/hashtable/dictionary interface that's really just a vector with linear lookup.

Then I think, hmm, maybe the standard containers should just do that. Maybe the authors of those should have some heuristic of "when to get fancy".

Re:In Defense of Linked Lists by KerrAvon on Friday November 04, 2022 @08:34PM (#33476250)
I think the cases where lookup is faster for a linearly scanned vector is where the hash computation overhead is greater than a linear scan. Assuming you have a good hash implementation, that should be true only for a small number of entries, where you need to determine "small" by measuring.
Re:In Defense of Linked Lists by asveikau on Friday November 04, 2022 @08:53PM (#33476418)
I think it's about locality and quickness of compare.

So if you have a small data structure and/or large cache, and the key is not complicated.

Re:In Defense of Linked Lists by bluGill on Friday November 04, 2022 @09:02PM (#33476506)
Even if the key is cheap, that it isn't in cache means that vector will be faster just because we avoid the cache miss of loading the value into memory.
Re:In Defense of Linked Lists by bluGill on Friday November 04, 2022 @09:01PM (#33476495)
Std::find_if works great if you want to treat a vector like a map. Plus you can have different keys if that is useful for your problem (look up employee by name, id, or address?)
Re:In Defense of Linked Lists by dabitude on Saturday November 05, 2022 @02:10AM (#33478462)
These are flat_map, flat_set, flat_hash_map, etc ...

See: https://en.cppreference.com/w/cpp/header/flat_map

Re:In Defense of Linked Lists by usefulcat on Saturday November 05, 2022 @04:31AM (#33479232)
I believe that flat_map and flat_set at least are sorted, so that binary_search/lower_bound can be used for lookups.

Linear search generally does outperform for small collections though (it’s better for caches and the branch predictor).

Re:In Defense of Linked Lists by asveikau on Saturday November 05, 2022 @05:03PM (#33485712)
C++23! The future is here.
Re:In Defense of Linked Lists by GuB-42 on Friday November 04, 2022 @08:56PM (#33476445)
> Often even for things that require lookup (i.e. vector outperforming a set)

I am always uncomfortable using higher algorithmic complexity. Sure, for small data sets, the vector will outperform the set, but it may not stay small forever. I may waste a millisecond now, but at least, I won't waste an hour if the user decides to use 100x the amount of data I initially considered. And using much more data than expected is a very common thing. It is a robustness thing more than optimization.

If you want both, there are staged algorithms, a typical example is a sort algorithm that goes insertion -> quicksort -> mergesort. Insertion sort is O(N^2), but it is great for small arrays, quicksort is O(N log N) on average but may become O(N^2) in some cases, and mergesort is guaranteed O(N log N) and parallelizable, but it is also the slowest for small arrays. For lists, that would be a list of vectors.

Re:In Defense of Linked Lists by jll29 on Friday November 04, 2022 @10:22PM (#33477144)
I like the staging idea, but curiously I haven't seen any papers investigating this.

Obviously, there is an overhead cost of the staging itself, which hits the use case for small data, and there is the question "From what data size onwards to use what algorithm?".

For example, I just had a look at sort in Clang's STL implementation, which seems to set a boundary at N=1000. Since the number is a multiple of 10, it looks like it might be arbitrarily picked, in any case there is no paper references in the comments to back it up.

Are people aware of formal studies that explore whether it is worth the trouble to inspect data structure and then to dispatch to different algorithms based on the findings?

Re:In Defense of Linked Lists by the_sleaze_ on Friday November 04, 2022 @10:59PM (#33477370)
You're saying you think there's still optimization to be done re. the N=1000 constant?

Other than that, I'd suggest that big O complexity is already telling you that the inspection is worth it. Assuming inspection of an array is constant.

Re:In Defense of Linked Lists by BeetleB on Saturday November 05, 2022 @01:48PM (#33483766)
> Sure, for small data sets, the vector will outperform the set, but it may not stay small forever.

In over 90% of SW applications written in C++, there is little to no uncertainty on the size of the data set. Most applications are written for a very specific purpose, with fairly well known needs.

If my data set is size N, and I can benchmark and show the vector outperforms the theoretical option up to, say, 20N, it's a safe choice to go with vector. Doing these analyses is engineering.

In any case, it's almost trivial to swap out the vector with other options when needed, if you plan for it.

Re:In Defense of Linked Lists by zelphirkalt on Saturday November 05, 2022 @04:50AM (#33479350)
I hope that senior engineer is also the one person, who will refactor things, if ever there are more elements in any of those vectors, making linear search slower than an actual set or other data structure. Oh and of course that senior engineer will also hopefully be the one monitoring the lengths of all those vectors in production.
Re:In Defense of Linked Lists by josefx on Saturday November 05, 2022 @05:37AM (#33479663)
> vectors, making linear search slower

The standard library gives you plenty of tools to maintain and search in a sorted vector. Often enough still faster than maps.

> Oh and of course that senior engineer will also hopefully be the one monitoring the lengths of all those vectors in production.

Doesn't a std::map have more space overhead than a vector?

Re:In Defense of Linked Lists by BeetleB on Saturday November 05, 2022 @01:51PM (#33483798)
I believe he was referring to the number of elements in a vector, to know when to swap with a different data structure - not the size in bytes.

But to your point - I once needed to do a key/value lookup for a large data set, and so of course I used a map. Then I ran out of RAM (had 80GB of it too!). So I switched to a vector and pre-sorted it and used binary_search for lookups (data set was static - populate once and the rest of the codebase didn't modify it). And of course, the RAM consumption was less than half that of the map.

Re:In Defense of Linked Lists by sfink on Saturday November 05, 2022 @02:22PM (#33484150)
Just describe your sorted list as "a balanced binary tree with implicit child links" and then you get credit for being fast, space-efficient, and using fancy data structure.