This is my main frustration with the push back against visibility modifiers. It's treated as an all or nothing approach, that any support for visibility modifiers locks anyone out from touching those fields.

It could just be a compiler error/warning that has to be explicitly opted into to touch those fields. This allows you to say "I know this is normally a footgun to modify these fields, and I might be violating an invariant condition, but I am know what I'm doing".

"Visibility" invariably bites you in the ass at some point. See: Rust, newtypes and the Orphan rule, for example.

As such, I'm happy to not have visibility modifiers at all.

I do absolutely agree that "std" needs a good design pass to make it consistent--groveling in ".len" fields instead of ".len()" functions is definitely a bad idea. However, the nice part about Zig is that replacement doesn't need extra compiler support. Anyone can do that pass and everyone can then import and use it.

> This allows you to say "I know this is normally a footgun to modify these fields, and I might be violating an invariant condition, but I am know what I'm doing".

Welcome to "Zig will not have warnings." That's why it's all or nothing.

It's the single thing that absolutely grinds my gears about Zig. However, it's also probably the single thing that can be relaxed at a later date and not completely change the language. Consequently, I'm willing to put up with it given the rest of the goodness I get.

Tbf, C++/C# style public/private/protected is definitely too restricted in many situations, and other more flexible approaches are pretty much still research territory.

They could do something like OCaml modules and signatures but more permissive. Module author writes the public signature and that's what the type checker runs against, but if you want, you can "downcast" the module to the actual signature, revealing implementation details.