What should be the naming convention of zig?

I would just like to ask for the calling convention of a zig program

I know constants are “const CONSTANTS_1: u16 = 3;”

But what about vars, structs, enums, function names?

Do you mean naming convention ? If so, you can refer this official zig doc#Names.

1 Like

aaand I just realised you might be asking abount naming conventions, after reading @dacec354 while writing this


‘Calling convention’ refers to how parameters are passed to function calls, and how the return value is passed back.

But I think I know what you mean regarding the other, non function, things.

consts and vars can be thought of as aliases to memory locations, which includes registers if its local, but they behave as though you have the actual value, so you can just think of them as the actual value for simplicity.

enums are just integers, with named values, the benefit is they are a distinct type from the backing integer, and it lets you have a smaller more descriptive set of values. The values start from 0 and go up in the same order as the fields are written, but you can override that field = 12.

structs are bundles of data, they follow the standard size/alignment rules any language does: the alignment is the largest alignment of its fields and the size is rounded up to a multiple of the alignment, if it isn’t already.
But the compiler is allowed to reorder fields to reduce padding and even insert extra data for safety (not implemented yet).
With exception to extern structs, which are just c structs: the fields are the exact order you defined them in, at the potential cost of increased size due to padding between fields.

Or packed structs, which are bit-packed, as opposed to byte-packed which is what the c packed attribute does. You can think of packed structs as an integer in a struct costume, great for bit fields.

If you want byte packing, use a normal or extern struct and set the field alignments to 1 name: Type align(1).

aaand I just realised you might be asking abount naming conventions, after reading @dacec354 while writing this

1 Like

Ah yes, naming convention…

so from your example…

const StructName = struct {
    field: i32,
};
const StructAlias = StructName;

fn functionName(param_name: TypeName) void {
    var functionPointer = functionName;
    functionPointer();
    functionPointer = otherFunction;
    functionPointer();
}
const functionAlias = functionName;

fn ListTemplateFunction(comptime ChildType: type, comptime fixed_size: usize) type {
    return List(ChildType, fixed_size);
}

fn ShortList(comptime T: type, comptime n: usize) type {
    return struct {
        field_name: [n]T,
        fn methodName() void {}
    };
}

// The word XML loses its casing when used in Zig identifiers.
const xml_document =
    \\<?xml version="1.0" encoding="UTF-8"?>
    \\<document>
    \\</document>
;
const XmlParser = struct {
    field: i32,
};

ok, struct is TitleCase, fn names are camelCase, var names are snake_case, is this correct?

1 Like

Would you mind updating the title to naming convention instead of calling convention? The current title could confuse people searching for calling convention topics.

Edited…it’s ok now…

For what it’s worth, screaming snake case is actual discouraged in the style, or at least in the std lib. I think you will only see it when matching a C Library interface.

1 Like

That is referencing a function body, which can be thought of as a comptime reference to a function.

To get a function pointer you need:

var functionPointer = &functionName;

ok…so “const constant_1 = 3;”, so its the same as the var naming right?

Ahh I guess the language doc makes a case for using camelCase for functionPointers which I think is a nice idea, that I hadn’t considered, I will edit my comment.

I mostly meant that functionName and &functionName have two different resulting types where the former can be used at comptime and the latter can also be used at runtime.

I think in the past getting a function pointer didn’t require using &, so I am wondering whether that example is still from that time, or whether it just doesn’t differentiate between function body and function pointer.

1 Like

There’s a few other uses where all uppercase is used and that aren’t just C library interfaces. For example, HTTP methods .GET, .PUT, .POST. The rule of thumb is to only use it when it matches existing conventions.

3 Likes

Thank you for the rule of thumb.

Do extern functions follow the camelCase convention?

I prefer using snake_case for functions as I find it easier to compose names & more reliably search the codebase for a name fragment that has been composed. Also, my IDE color codes functions differently from other types, so while there is a benefit for camelCase identifying multiWord functions by shape, the color is a reliable indicator of it being a function…especially considering that many functions are 1 word. And some functions that take a comptime type to return a typed struct seem to use `PascalCase(comptime T: type)`

I’m also willing to compose_snake_and_camelCase together to preserve the shape of the name fragment…so a case-sensitive search for camelCase will reliably include compose_snake_and_camelCase along with camelCase…or POST_user/GET_user

I’m curious…would many people refuse to use a library because it uses snake_case for function names? My experience is that individuals tend to care less than teams…so I may have answered my own question. But I do feel that immutable name fragment casing helps with complex codebases. Where a simple case-sensitive global search will reliably show every place a concept is used.

when doing extern const/var/fn the name must match the symbol from the lib/obj you are using exactly. if you want to use a different name than the symbol, you can do const foo = @extern(*Bar, .{ .name = "baz"});.

Conventions exist for a reason, but are also not hard rules, you can break them and bear the consequences (whatever that is).

In the case of zigs naming convention, it exists to help differentiate different categories of things, while your editor may provide other ways to differentiate them that are specific to your setup.
There lurks the cost of breaking this convention, it makes it harder for others to read your code.

Most people won’t have a hard time reading code that doesn’t follow the naming convention, and won’t refuse to use your library because of it.

I will point out the various disabilities around sight certainly have an impact here. I know someone who dislikes rust because their dyslexia doesn’t play nice with the lack of braces around if/match/etc conditions.

Since you brought up your editor highlighting functions, I will bring up that my editor (helix) and others can search and filter symbols using information from an lsp. So i can search for functions specifcally without excluding ones that dont follow convention.
unfortunately zls only supports per file symbols, and not whole project symbols

But not every has or wants such features, I dont think its a big ask to follow convention to be more accessible to those who do need it.

1 Like

Conventions exist for a reason, but are also not hard rules, you can break them and bear the consequences (whatever that is).

Such is life. You bear the consequences of breaking rules…and you bear the consequences of following rules.

For example as a codebase grows complex…being able to quickly scan & understanding large amounts of code by minimizing cognitive load on low level understanding opens up higher level thinking. Such is the value of conventions that address the crux of the challenges. Complexity is difficult to generalize & articulate as a challenge…It’s much easier to bike shed. Not to say that camelCase vs snake_case is bike-shedding, but strict adherence to one or the other is secondary to being able to quickly scan & understand the codebase.

An easy to point out example is searching through Python (or Rust) & Javascript graphql interactions…where Python’s convention is snake_case and Javascript’s convention is camelCase. It can be a challenge to reasoning about long chains of data & execution flow especially when the convention of 1 language is different from another.

Since you brought up your editor highlighting functions, I will bring up that my editor (helix) and others can search and filter symbols using information from an lsp. So i can search for functions specifcally without excluding ones that dont follow convention.

Helix’s smart-case search looks great. Would a search for username result with a getUserName function and a user_name variable?

But not every has or wants such features, I dont think its a big ask to follow convention to be more accessible to those who do need it.

I like how you phrased it by audience. It does feel right to be for libraries to follow conventions. With apps having more leeway to follow their own conventions.

Libraries tend to have a simpler domain model anyways. Though there may be libraries that are “domain libraries” that have many interdependent concepts or touch multiple platform (such as GraphQL). Those are less common and the trade-offs may be different.

Re: usability, my vision is not what is used to be. And snake_case is easier for me to read. But someone else will say camelCase is easier to read. So ease of reading is somewhat subjective. I personally like the shapes of the words being distinguishable as well…so I can live with following the rules when writing a library unless there’s a good reason (that most people would acknowledge) to break the rules.

2 Likes

yes, it uses fuzzy searching, for this at least, so you can be quite vague with searches.

2 Likes