> The Zig documentation states that "Identifiers are never allowed to "hide" other identifiers by using the same name."<p>I see this desire to get rid of shadowing all the time, but in practice it's such a disruptive restriction.
> Speaking of structure fields, they're always public. Structures and functions are private by default with an option to make them public. But struct fields can only be public.<p>This feels like a mistake to me. I own and maintain a C library, and lack of private struct members is one of the things that causes the most problems. My users frequently reach into struct members even though I really do not want them to. This causes problems when those members have subtly different semantics than what they expect. It's even worse when I want to change the internal representation, and I have to track down all my users' code and change it accordingly.<p>In C, my only options are:<p>(1) Define the structure in a .c file instead of .h. This works great in cases where I can take the performance hit of not being able to inline accesses of those struct members. But for performance-critical structures where I need to be able to inline, this is not an option.<p>(2) Make the member names something like private_foo, internal_foo, etc. and hope my users take the hint. But this also makes my own code more ugly and creates longer lines that are more likely to wrap.<p>Unfortunately Zig is even less capable than C in this regard, because Zig takes away option (1). Since there is no header/source split in Zig, I cannot make a struct opaque by defining it in a source file only. Though I do see that there is "opaque {}", perhaps that plus some casting could accomplish a similar thing?<p>I see that rationale for not having private struct members was given here: <a href="https://github.com/ziglang/zig/issues/9909#issuecomment-942686366">https://github.com/ziglang/zig/issues/9909#issuecomment-9426...</a><p>> The idea of private fields and getter/setter methods was popularized by Java, but it is an anti-pattern. Fields are there; they exist. They are the data that underpins any abstraction. My recommendation is to name fields carefully and leave them as part of the public API, carefully documenting what they do. [...] In my subjective experience, public fields generally lead to better abstractions by eliminating the temptation to attempt full encapsulation, when the more effective strategy is to provide composable abstraction layers.<p>Java does indeed represent an anti-pattern of verbose and frequently trivial getters and setters. But newer languages like C#, Swift, and Dart have more elegant and low-overhead syntax for properties, even allowing a property to move between being an actual field member and being derived, without breaking users.<p>As a library maintainer, full encapsulation is very important for evolution of a system over time. The only way for layers to truly be layers is if the contract at each layer boundary is clear. Otherwise the layers gel together and you cannot safely change any one layer independently.
> Speaking of structure fields, they're always public. Structures and functions are private by default with an option to make them public. But struct fields can only be public. The recommendation is to document allowed/proper usage of each field.<p>> I don't want to editorialize this post too much, but it's already caused the type of issues that you'd expect, and I think it'll only cause more difficulties in a 1.x world.<p>I wish the author elaborated a bit more here because I've always been interested in what problem exactly `private` (and all the language complexity/overhead) that comes with it solves. for something like C# it kind of makes sense because it's a language built around chaining method calls and IntelliSense, so the user types `foo.` and IntelliSense shows literally everything you could want to do with that `Foo` instance, excluding `private` members/methods. I can see the use-case for this in a corporate-type setting. in absence of this feature (which I <i>believe</i> is the case for Zig?), what possible difficulties can be caused, in practice?
Regarding naming conventions, there is an issue about switching to snake case for functions as well, the main rationale being there is no difference between snake_case and camelCase for one word identifiers:<p><a href="https://github.com/ziglang/zig/issues/1097">https://github.com/ziglang/zig/issues/1097</a>
I don't usually like participating in bikeshedding, but the @ annotation feels like PHP's $ to me in that I don't see why it needs to exist. The language design could've easily just left that out and I don't think anything would be lost.<p>Other than that, I'm definitely excited for Zig as a potential C++ replacement.
(Non-user of Zig here.)<p><pre><code> // tea.zig
full: bool = true,
const Self = @This();
pub fn drink(self: *Self) void {
self.full = false;
}
// other.zig
const Tea = @import("tea.zig");
</code></pre>
This example seemed to stop just short of the really interesting bit: what if other.zig called Tea.drink()? Would it set Tea.full to false? Maybe this is obvious to Zig users, but coming from C++, that would be a violation of const correctness.<p>In C++ (thinking of classes rather than files), you wouldn't be able to call the drink method of a const object because it's not marked as a const method. Or, if it was marked as a const method, you wouldn't be able to modify full from in drink. You could get around this by marking full as mutable, which means you're going to deliberately violate const correctnees, but at least you have to be explicit about it. (In theory mutable is meant for things like caches that don't affect the visible behaviour of the class.)
Re 9, would it be possible to change the signature of expectEqual from<p><pre><code> pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void
</code></pre>
to<p><pre><code> pub fn expectEqual(expected: @TypeOf(actual), actual: anytype) !void
</code></pre>
What would the downsides be?
Coming from C, I always see these "Self" variables/types as counter-intuitive, and contribute to those cases where a function requires a parameter which I don't have to supply (just for these functions accepting "Self"), which could be an exception instead of a rule. I would rather prefer the C++ "this" keyword usage.<p>Also, do "Self" kind-of variables occupy memory?<p>How can I declare a (packed) struct describing a payload in a way that the struct can be then sent "as is" as a network packet?<p>Let's say this struct has a "calculateChecksum()" method. Will I need to declare "Self"? If so, will be "Self" part of the struct's memory layout?
Some parts of the Zig syntax reminds me of the old K&R style function declaration, that seemed absurd and was replaced at some point, but it was released, used in production and defended for a while.<p>There is often a strong rationale behind clumsy syntax decisions, I hope they will fix those quirks.
> Functions are camelCase<p>> Types are PascalCase<p>> Variables are lowercase_with_underscores<p>Just why? It does not seem like the same language that used to treat tabs as a compiler error. Looks like the worst of every worlds to me. Why not just stick to one style?
why this wouldn't be possible (or not preferred) without the dot?<p><pre><code> var tea = Tea{.full = true};
</code></pre>
like:<p><pre><code> var tea = Tea{full = true};</code></pre>
In my compiler I loosely coerce comptime_int's to int's if needed by subsequent API's.
You also need to expand or truncate it's size on demand. E.g. C compilers do that.<p>zig just error's, which is a silly behaviour.
Correct me if I'm wrong, but it really seems like bad const inference that `x` from the 8th example is typed as a `comptime_int`. Is all comptime inference only done at the point of declaration?
Please don't do "const Self = @This();" if the type isn't generic. It is pointless, redundant, ugly.<p>What issues could public struct fields have caused?