Any reasons to not use "file as singleton" paradigm in zig

I am writing app (not libary) so I don’t need generic struct or even in my situation several instances. I need just a singleton so are there any reasons (except obviously a feeling that it is wrong) to not just declare pub var ... and necessary functions in file and use it as singleton/global state?

Primarily - testing. Doing this can make it quite hard to write sensible tests.

8 Likes

My primary reason is that I hate singletons, because of years of being burned by them (both when I initially used them myself and then when others used them, but that was also in old c++ times which may have something to do with it…).

I find it preferable to just explicitly create your instance and use it, which is relatively simple in Zig and also has the benefit that you can more easily refactor stuff and understand the code.

I also think that the idea of “I only need one of these” often turns out to be a false assumption, right in the moment when you have written so much code that it becomes a pita to change it.

7 Likes

I’d invert the question: why not add var app = … at the start of the main function, and then just pass the pointer to app around?

5 Likes

Because it is one more argument to pass. I am tired of io + gpa in each call + in vulkan you can add from one to three additional variables you always pass around…

1 Like

Given that you already pass one argument around, you can make App that argument, and store allocator as a field of the app.

I usually regret it if I don’t pass something around, but, if I pass something, I might as well pass everything.

2 Likes

I’ve been doing this for years (and still doing it), and from my practical experience it has some advantages and some disadvantages.

The main problem I have experienced is that it is harder to define your dependencies (it’s not clear from the function signature what the function can/will use), which can lead to initialization order problems and make it more difficult to do unit tests as well as make it harder to read some of the code. (though these are not a concern if you keep things simple, like in a small app, or just simply don’t do many unit tests)

The advantages are obvious, you need to pass around less variables, and, especially in small programs, it just feels quicker and more direct. Furthermore, and this is specific to Zig, you have more control over what variable/field to make public.

None of these are particular strong advantages or disadvantages in my opinion, I think it’s mainly a matter of preference.

5 Likes

I tend to create parameter sets of some sort.

App being a container for all of them, but some functions only need a subset of that. And initialize it all through main.

This also has some cons.

Often i do find just passing App can be simpler and I’ll end up using more than i thought. Then later on refactor to pass the subset through when the code is more stable and i know ‘for sure’ that only x number of systems are ever needed.

Of course, that refactor is always low on the list of things to do- and I only care about it at all from this tingling in the back of my head about passing way more info than needed or should ever be used by some function.

2 Likes