The dot "." overuse

That dot in .{ } doesn’t mean anything on its own, it’s just part of .{ and is not neally consistent with the other field/namespace access dots.

Just think of the whole .{…} as a special kind of braces used for tuples/struct literals, because normal {…} braces already mean other things.

(When anonymous struct literals were added in Zig 0.6.0, simply using { } (like in C) was not possible because that would have led to certain parse ambiguities, so the abominable .{ } syntax was invented as a hack, with the hope that the dot could be removed later, but unfortunately this has not happened yet, see get rid of the `.` in tuples & anonymous struct literal syntax · Issue #5039 · ziglang/zig · GitHub)

Thanks so much to everyone helping me try and understand this !

Nice necrology of Github issue, it’s interesting to see what was their mind at, at that time.

I find this usage, concise and unambiguous. Also very clever use of the explicitness of the type system (and it’s hints). I really like this from zig

This one feels really odd, from the others, I mean

it’s actually the same as the .{ .field = a } syntax. the difference is that if you do not name the fields, then such a literal is of a tuple type.

Yeah, understand that it is a tuple, but it still feels weird, I mean, after getting accustomed to the other (nice/cool) usages

I like that you need to add dot before field names in initializer because it makes writing init functions easier:

fn init(source: []const u8, index: u32) Lexer {
    return Lexer{ .source = source, .index = index, .line = 0 };
}

If there was no dot before field names the above would look very weird and would maybe not even work without changing the names of the paremeters.

The main reason I heard to support some_pointer.field instead of some_pointer->field is that there can’t be uncertainty about what it does :smiley: and it makes refactoring easier (if you change from pointer to struct and vice-versa).

3 Likes

I’m remembering from other discussions that this is no longer true, or is being changed. In other words, the first example will always copy (never pass a pointer) and the second example is therefore necessary to avoid copying.

1 Like

One particularly unusual use of “.” is as a binary operator that converts a pair of integer literals into a float literal:

const another_float = 123.456;

One a more serious note, I generally look at it as a sort of “part of ” operator. If in doubt, look at the type of (or contents of) the thing to the left, and you will figure out what the thing to the right is.

I also like the observation someone made that it’s where ZLS can infer what comes next. I’d never really noticed that until now.

It’s certainly better than C’s overloaded operators, though that’s not hard:

*abandon*= * all & * & hope * * * now;  // Valid C code
3 Likes