| I’d like to chime in on the all-fields-are-public debate. If I’m a library author and release something which exports a struct… I can never change any of the struct’s internal data structures? I can never rename a field. Or delete a field. Or change what should be an internal field’s type. And that makes non-breaking changes as a library author much more challenging, which may be a very serious problem for Zig, especially if the stdlib isn’t Go-style “batteries included”. I would seemingly need to version the structs to work around this: ArrayListV1, ArrayListV2… Part of the beauty of great code is in its API design. And forcing my libs to document: /// Don’t touch this field. Without any way for me to hide the field itself from users or prevent them from using it is very strange. Users can’t intuit what to use and not use without studying documentation, which a well-thought out API might improve. Go has been extremely successful in part due to its nicely thought out APIs in the stdlib. They have certain fields which anyone would care to use, and all the rest are—for your purpose as a user—not there. And this same design has made refactors of libraries/packages (without breaking changes for users) very easy. |
I now think that an external tool is the way to go. C++ has field access control, but for some projects, that's not enough, so they have an external layer of access control, like Chromium DEPS (sample: https://source.chromium.org/chromium/chromium/src/+/main:ui/... )
And use cases of libraries are different. Perhaps most uses of library X use it as a black box and should never directly access structure fields, but project X′ integrates closely with X. That's hard to express in the language since it's hard to express purely within X at all. Maybe you need a `foo.@i_know_this_is_private_but_let_me_use_it_anyway(bar)`, like Python's underscore convention.
Or you have an external static analyzer using some sort of allow and deny rules. Maybe library X declares `Deny *` but project X′ overrides it with an `Allow X.foo.bar`. The rules can be explicit, automatically enforced, and subject to code review, so it's OK.