OK, here is the complete file, it’s only just been started and I have issues already, despite the fact I have created loads of other Structs in my code and other small Zig projects, I am still new to Zig.
src/editor_core.zig:34:13: error: no field or member function named 'len' in '@typeInfo(@typeInfo(@TypeOf(editor_core.Editor.init)).@"fn".return_type.?).error_union.error_set!editor_core.Editor'
expect(e.len() == 0);
~^~~~
src/editor_core.zig:34:13: note: consider using 'try', 'catch', or 'if'
Clearly, the init() call works, declared as a public fn, but the len() it says is not a member… totally and utterly bemused and confused at this point, especially as I thought I was starting to “get it” LMAO
The only significant difference I can see is init() has no Self, and len() has a Self which is immutable and append() also has a mutable Self.
test "Test initial state" {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
const e = try Editor.init(allocator);
try expect(e.len() == 0);
}
This level of frustration takes me back some 20 odd years when I started learning Haskell… the real secret to progress is not sometimes the language but learning to decipher the compiler errors to the point they make sense.
I really really went back and stared hard and as usual the answer is there, my brain just couldn’t get through the noise to read the signal!
If somebody ends up using an ArrayList that wasn’t initialized, because it was default-initialized to undefined (and usually you would expect to get an error if you didn’t initialize an ArrayList somewhere), then they will likely trigger a Segfault/crash (in the good case) or cause the program to do unexpected/buggy things (like corrupt its own memory, change and access different pointers) (in the bad case).
Default initializing a field to undefined is almost never a good idea. Most of the time it would be better to create explicit initial empty values, or initialization functions that return an instance instead.
(I think fields that default to undefined should be reserved to internal buffers that are automatically initialized lazily once the data-structure is used (based on other fields in the struct), or for situations like that, but even there you could avoid setting a default value that is undefined on the field itself and instead set it explicitly where the instance is constructed)
var instance: ManagerWithComplexInternalState = try .init(allocator);
defer instance.deinit();
// function is used as a post-init/pre-use step to create internal
// links or pointers that require a stable memory address for example
// for self-referential structures
instance.setup();
But I am not entirely sure what specifically you mean with setup and teardown, I think those can mean many different things depending on the context. Can you clarify?
I was just asking what the “common Zig pattern” is if a bunch of tests all have a common setup, I guess the obvious answer is to define a function and just call it but then would that function be included in a build other than test?
I think that is just done there so that the different array lists can all use the name list, otherwise that isn’t really necessary.
You can just define a function and call it from the test, functions that aren’t used will be ignored by the compiler, because they are only lazily analyzed/compiled when they are actually used. So it wouldn’t be included in other builds, if those don’t use the function.