Zig's new LinkedList API (it's time to learn fieldParentPtr)
New intrusive API and Zig’s design goals
- New std linked lists are intrusive: user structs embed node fields and use
@fieldParentPtrto recover the parent. - Several commenters say this matches Zig’s “low-level, explicit, data‑oriented” ethos and the community’s existing use of
@fieldParentPtr(including for inheritance-like patterns). - Others feel it’s a “net negative” for higher-level application code, preferring generic, encapsulated containers with simpler APIs.
Type safety and @fieldParentPtr
- Major thread around whether
@fieldParentPtris “typesafe”. - Consensus: it’s only partially safe. The compiler can check that the type has a field of that name and matching type, but cannot verify that the pointer actually came from that field; misusing it causes unchecked illegal behavior.
- Example: passing a pointer to an unrelated
i32compiles but is illegal per the language reference. - This is seen as a serious footgun, especially now that std lists require it for iteration. Some note there are plans to make it safer, but not yet.
Generics, comptime, and functional-style APIs
- Old list was generic
SinglyLinkedList(T); new one is not. - People ask how to write reusable functions like
map/filteror list-parameter APIs. - Answers: use
comptimetype parameters, pass field names ascomptime []const u8, and operate imperatively with loops. - Some argue Zig intentionally discourages generic, functional-style abstractions (no closures, weak lambda ergonomics); others find “you just don’t” an unsatisfying answer and point out first-class functions do exist.
Performance and memory layout arguments
- Pro-intrusive camp:
- Fewer allocations when objects already exist; node is inside the object.
- Better cache locality vs separate node allocations; easy to put the same object in multiple lists via multiple node fields.
- Smaller code size because list APIs are no longer generic.
- Skeptics counter:
- The old generic list already embedded
Tin the node, so layout and allocation count were often identical. - Real performance win is mainly multi-list membership and some niche patterns; claims about “higher performance” lack concrete benchmarks.
- Intrusive design couples data types to specific containers and can pollute structs with multiple node fields.
- The old generic list already embedded
Use cases and prevalence of linked lists
- One side: linked lists should be niche; arrays, vectors, and hashes are usually better on modern hardware (cache locality, simpler semantics).
- Other side: they are widely used in kernels, event loops, allocators, schedulers, and other systems code (often intrusive), especially where allocations are constrained or objects live outside the container.
- Several examples are given: OS kernels, network stacks, coroutines, wait-free / lock-free queues, LRU structures, allocator internals.
API ergonomics and abstraction
- Some wish Zig exposed a typesafe generic wrapper atop the intrusive primitive, keeping
@fieldParentPtrinternal for most users. - Others argue Zig intentionally uses “friction” to steer people away from linked lists unless they really need them, and towards simple loops and more conventional containers.