Self is used in the standard library for non generic types every now and again.
As for public fields, the 0.9 change to allocator comes to mind. This was written off as a minor change, because Zig is pre 1.0. But what I haven't heard (and 100% upfront, I haven't looked hard), is how Zig plans on dealing with it post 1.0. Like, where are we in the gradient of: "1.0 will never break the public API (struct fields included)" to "deal with it".
1.0 for Zig is going to mean not only never break the API, but also that we'll be pretty much done with the language. The current idea is to release v1 only after a few releases that only contain bug fixes.
> As for public fields, the 0.9 change to allocator comes to mind.
That's a good example of why it makes sense for Zig to have all fields be public: the change that we did to allocators has important implications that in Zig we don't want to hide behind a `private` descriptor. This is obviously not a universal truth, but it makes sense for a low-level programming language that cares about the details.
> Self is used in the standard library for non generic types every now and again.
I agree with the parent poster, those should probably be removed, as they don't really help make the code more readable or provide any other advantage. A overhaul of the stdlib is planned, but we're not there yet, as we're still busy working on the package manager and incremental compilation.
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.
When I first played with Zig (and I haven't done more than play), I had a similar view. I suspect that the adoption of Zig in certain current C niches may be hampered by the inability to express things like the opaque pointer idiom, mandated by coding standards like CERT C and MISRA[ble] C.
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.
It's impossible to state universally what should or should not be considered part of the public api of a struct when it comes to low-level programming.
In some cases the exact layout of the struct needs to stay stable. In others the contents don't matter, only that the size doesn't change. In others still, none of those properties matter and it's just a matter of keeping names and types stable, and that every new field that gets added has a default value so that old initialization expressions keep working.
This is just to name a few cases among many others. In the end you will need to specify in the docs what it is that you, the library author, want to consider part of the public API and what is considered an implementation detail.
> 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?
Stucts in most modern languages are NOT guaranteed to have any particular layout unless you explicitly ask for it--so you don't have that guarantee to begin with. This enables them to rearrange the struct for better packing or AoS/SoA transformations.
If someone grovels in your structs and gets burned, well, that's their own fault. I'll go further, if someone grovels in a library struct, they have failed. I'll go even further, if someone has to grovel in a library struct, the library has failed.
In addition, in embedded contexts I regularly have to grovel in structs to work out some bug. "static" is often the bane of my existence in C because compilers often throw away or hide references to those variables. However, they may be crucial to running down state.
I work in a language where all fields are public and it is indispensable in debugging things. You DO NOT want your datatypes hiding things under the hood.
At best, if zig does want to make fields private, they should still be visible, but the compiler should disallow writing to them.
I believe you, but I haven't encountered anything like this in my work in a higher-level language, and this is my first push into manual memory management since I studied C in college many years ago.
Can you offer some examples of times when it has been indispensable, so that I can understand when this is useful?
don't remember any off the top of my head. I use elixir, I do often dive into the data structures with IO.inspect(..., structs: false) which exposes all of the "hidden" fields. Enough so that I know how to do this without having to look it up.
I suppose you could also use the debugger, but I value my time.
As for public fields, the 0.9 change to allocator comes to mind. This was written off as a minor change, because Zig is pre 1.0. But what I haven't heard (and 100% upfront, I haven't looked hard), is how Zig plans on dealing with it post 1.0. Like, where are we in the gradient of: "1.0 will never break the public API (struct fields included)" to "deal with it".