I am new to Zig so idk if I’m missing something basic here, but the behaviour seems strange all the same.
I have moved my tests into a main function just to simplify testing with lldb.
I have the following code:
const std = @import("std");
const expect = std.testing.expect;
const assert = std.debug.assert;
pub fn LinkedList(comptime T: type) type {
return struct {
pub const Node = struct {
node_prev: ?*Node,
node_next: ?*Node,
data: T,
};
node_first: ?*Node,
node_last: ?*Node,
len: usize,
fn append(self: *LinkedList(T), data: T) usize {
if (self.len == 0) {
var node = Node{
.node_next = null,
.node_prev = null,
.data = data,
};
self.node_first = &node;
self.node_last = &node;
} else {
var node = Node{
.node_next = null,
.node_prev = self.node_last,
.data = data,
};
const last_ptr = &(self.node_last orelse unreachable);
last_ptr.*.node_next = &node;
self.node_last = &node;
}
self.len += 1;
return self.len;
}
fn get(self: *LinkedList(T), index: usize) error{IndexOutOfBounds}!T {
if (index >= self.len) {
return error.IndexOutOfBounds;
} else {
var node_ptr = &(self.node_first orelse unreachable);
if (index > 0) {
for (0..index) |_| {
node_ptr = &(node_ptr.*.node_next orelse unreachable);
}
}
return node_ptr.*.data;
}
}
};
}
pub fn main() !void {
// TEST APPEND
var list = LinkedList(usize){
.node_first = null,
.node_last = null,
.len = 0,
};
try expect(list.len == 0);
try expect(list.node_first == null);
try expect(list.node_last == null);
_ = list.append(10);
try expect(list.len == 1);
var node = list.node_first orelse unreachable;
try expect(node.data == 10);
node = list.node_last orelse unreachable;
try expect(node.data == 10);
_ = list.append(2);
try expect(list.len == 2);
node = list.node_first orelse unreachable;
try expect(node.data == 10);
node = list.node_last orelse unreachable;
try expect(node.data == 2);
for (0..10) |i| {
_ = list.append(i);
node = list.node_last orelse unreachable;
try expect(node.data == i);
}
try expect(list.len == 12);
// TEST GET
var list2 = LinkedList(i32){
.node_first = null,
.node_last = null,
.len = 0,
};
try expect(list2.len == 0);
try expect(list2.node_first == null);
try expect(list2.node_last == null);
_ = list2.append(10);
try expect(list2.len == 1);
const data_first = try list2.get(0);
const node2 = list2.node_first orelse unreachable;
try std.io.getStdOut().writer().print("data_first = {d}\nnode.data = {d}\n", .{ data_f
rst, node2.data });
try expect(data_first == node2.data);
try expect(data_first == 10);
_ = list2.append(2);
try expect(list2.len == 2);
try expect(try list2.get(0) == 10);
try expect(try list2.get(1) == 2);
}
First the test output:
data_first = -1554706984
node.data = -1554706984
error: TestUnexpectedResult
/opt/zig0.14/lib/std/testing.zig:580:14: 0x10de25f in expect (linked_list)
if (!ok) return error.TestUnexpectedResult;
^
/home/volin/programs/zig-projects/linked-list/src/main.zig:108:5: 0x10deb4e in main (linked_list)
try expect(data_first == node2.data);
^
data_first = 1338275224
node.data = 1338275224
error: TestUnexpectedResult
/opt/zig0.14/lib/std/testing.zig:580:14: 0x10de25f in expect (linked_list)
if (!ok) return error.TestUnexpectedResult;
^
/home/volin/programs/zig-projects/linked-list/src/main.zig:108:5: 0x10deb4e in main (linked_list)
try expect(data_first == node2.data);
^
So when I step through this code and examine values everything behaves as expected up to this point.
fn get(self: *LinkedList(T), index: usize) error{IndexOutOfBounds}!T {
if (index >= self.len) {
return error.IndexOutOfBounds;
} else { // GOOD HERE
var node_ptr = &(self.node_first orelse unreachable);
if (index > 0) { // BAD HERE
for (0..index) |_| {
node_ptr = &(node_ptr.*.node_next orelse unreachable);
}
}
return node_ptr.*.data;
}
After initializing node_ptr self.node_first.node_next and self.node_first.data both get replaced with unexpected data.
I only get one image as a new user so enjoy this wonderful graphic with lldb states:
I’m using this as an opportunity to learn, but I also find this behaviour to be unexpected. I’d love to know if there is something I am failing to understand about how zig works. If this seems strange to others I’d also love to know if it’s worth reporting as a bug

