Why is declaration publicity a feature of Zig?

You can hide fields too:

const PublicFoo = struct {
    gadget: Gadget,

    pub fn create(allocator: Allocator) !*PublicFoo {
        var b_raw = try allocator.alloc(u8, @sizeOf(PublicFoo) + @sizeOf(PrivateBar);
        var foo_ptr: *PublicFoo = @ptrCast(@alignCast(b_raw));
        // Fill in public stuff
        foo_ptr.gadget = .widget;
        var bar_ptr: *PrivateBar = @ptrCast(@alignCast(b_raw[@sizeOf(PublicFoo)...]));
        // Fill in private stuff
        // ...etc
        return foo_ptr;
    }

    // Add a little helper fn to get your private stash,
    // remember to free it, and so on. Done.
};

I’ve done this, not to hide fields, but to have variable-sized allocations which are dense in memory. It works.

I find Zig’s publicity rules fairly pragmatic. Especially when working in teams, being able to separate the intended API from the details is a good way to stay out of trouble. For the most part, hiding data is not the same kind of useful, but if it is, there’s stuff like the above, and *anyopaque. It can be done.

I thought it would be nicer, at one point, if pub followed container scope, not file scope, so a bit stricter. Just for the consistency of it, or mostly.

Changed my mind about that. A file makes sense as the visibility boundary, because it’s literally everything which is visible. When working, I’m not going to notice the consistency: I would notice the futility of hiding things from myself, however.

6 Likes

Zig should look at Python. “We are all consenting adults here”.

There is too many private stuff in std. I’m working on perf intensive code, and there a few sloppy functions in std and you can’t rewrite them without forking the full file because they call private APIs.

3 Likes