Skip to content

Code Styling (Detailed)

Edward Dean edited this page Sep 9, 2019 · 1 revision

Style Guidelines

We welcome all contributions, be it bug reports, feature suggestions or pull requests. We follow the style mandated by zig fmt so make sure you've run zig fmt on your code before submitting it. But in addition, we also like to order a file's contents to be as follows. This allows all files to be uniform and easy to follow across the code base.

Naming

In addition, users should follow the naming standard set out in the Zig documentation: Style-Guide

Global constants should be block capitalised with words separated by underscores:

const GLOBAL_CONST: u16 = 0;

Typing

  • Types for global variables/constants need to be explicitly defined.
  • Types for local variables/constants shouldn't be defined unless the compiler gives an error.
  • Functions that return an error set, the error set must be explicitly declared. For example: PrintError!void - Yes, !void - No.

Commenting

Commenting throughout the code base is greatly received so you can explain what is going on. Pls comment code.

Comments maximum length is 100 characters (including leading whitespace and //).

Document commenting

Everything. pub and non-pub functions/variables/constants. Please follow the following template for doc comments:

///
/// Description of the function/variable/constant
///
/// Arguments:
///     IN param_name_1: ParamType1 - What the parameter is.
///     OUT param_name_2: ParamType2 - What the parameter is.
///     IN/OUT param_name_3: ParamType3 - What the parameter is.
///
/// Return: ReturnType
///     What the return is.
///
/// Error: ErrorSet
///     ErrorSet.Error1 - What the error is.
///     ErrorSet.Error2 - What the error is.
///
  • Note the leading and trailing ///

  • Doc comments for constants/variables don't need the leading and trailing ///, this is for function doc comments.

  • Imports/externs/tests don't need doc comments.

  • For the arguments, the first first part is whether the parameter is a input to the function (IN), a output (OUT) or both (IN/OUT). If the function takes no arguments, then the argument section shouldn't be included in the doc comment.

    • An example of a input parameter can be a simple number, 5.
    • An example of a output parameter can be a pointer which gets initialised by the function being called.
    • An example of a input and output parameter can be a Self object where both the content of the parameter is used in the function and is updated in the function being called.
  • For the return comment, after the Return: is the return type of function. If the function returns void, then the return comment shouldn't be included in the doc comment.

  • For the error comment, after the Error: is the error set that can be returned. If the function doesn't return an error, then the error comment shouldn't be included in the doc comment.

  • If a comment for a arguments/return/error is longer than 100 characters, then the next line need to be aligned to the start of the comment:

    ///
    /// Description of the function/variable/constant
    ///
    /// Arguments:
    ///     IN param_name_1: ParamType1 - What the parameter is. blah, blah, blah, blah, blah, blah,
    ///                                   blah, blah, blah, blah.
    ///
    /// Return: ReturnType
    ///     What the return is. blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, blah,
    ///     blah, blah, blah, blah.
    ///
    /// Error: ErrorSet
    ///     ErrorSet.Error - What the error is. blah, blah, blah, blah, blah, blah, blah, blah,
    ///                      blah, blah, blah, blah.
    ///

Ordering

To have all files be consistent across the whole code base, we would like to following ordering to be followed:

Imports

  • Zig std imports. These include std, builtin, ... Anything that is standard to the Zig language.
  • Non-public user made imports
  • Public user made imports
  • No doc comments
  • Anything that comes from an @import() can also be included here. These should be in a sensible order.
  • If you are importing, for example, one function from a file, then still import the file, then access the function. const assert = @import("std").debug.assert; - No.
const std = @import("std");
const assert = std.debug.assert;

const syscall = @import("syscall.zig");

pub const log = @import("log.zig");

Global assembly

  • Doc comment
/// What this assembly does
comptime {
    asm (
        \\.global my_func;
        \\.type my_func, @function;
        \\my_func:
        \\  lea (%rdi,%rsi,1),%eax
        \\  retq
    );
}

Enum

  • Non-public extern enum
  • Public extern enum
  • Non-public packed enum
  • Public packed enum
  • Non-public normal enum
  • Public normal enum
  • Anything within the namespace of the enum follow the same ordering
  • Doc comment
/// What this enum is.
const ExternEnumType = extern enum {
    /// What A is.
    A,

    /// What B is.
    B,
};

/// What this enum is.
pub const ExternEnumType2 = extern enum {
    /// What A is.
    A,

    /// What B is.
    B,
};

/// What this enum is.
const PackedEnumType = packed enum(u2) {
    /// What A is.
    A,

    /// What B is.
    B,
};

/// What this enum is.
pub const PackedEnumType2 = packed enum(u2) {
    /// What A is.
    A,

    /// What B is.
    B,
};

/// What this enum is.
const EnumType = enum {
    /// What A is.
    A,

    /// What B is.
    B,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN self: EnumType - What this parameter is.
    ///
    /// Return: bool
    ///     What the return is.
    ///
    pub fn foo(self: EnumType) bool {
        return self == EnumType.A;
    }
};

/// What this enum is.
pub const EnumType2 = enum {
    /// What A is.
    A,

    /// What B is.
    B,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN self: EnumType - What this parameter is.
    ///
    /// Return: bool
    ///     What the return is.
    ///
    pub fn foo(self: EnumType2) bool {
        return self == EnumType2.A;
    }
};

Union

  • Non-public extern union
  • Public extern union
  • Non-public packed union
  • Public packed union
  • Non-public normal union
  • Public normal union
  • Anything within the namespace of the union follow the same ordering
  • Doc comment
/// What this union is.
const ExternUnionType = extern union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
pub const ExternUnionType2 = extern union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
const PackedUnionType = packed union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
pub const PackedUnionType2 = packed union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
const UnionType = union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
pub const UnionType2 = union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

Tagged union

  • Non-public tagged union
  • Public tagged union
  • Anything within the namespace of the tagged union follow the same ordering
  • Doc comment
/// What this union is.
const TaggedUnionType = union(enum) {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN self: TaggedUnionType - What this parameter is.
    ///
    /// Return: bool
    ///     What the return is.
    ///
    pub fn bar(self: TaggedUnionType) bool {
        return switch (self) {
            TaggedUnionType.Int => |i| i != 0,
            TaggedUnionType.Float => |f| f == 0.0,
        };
    }
};

/// What this union is.
pub const TaggedUnionType2 = union(enum) {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN self: TaggedUnionType - What this parameter is.
    ///
    /// Return: bool
    ///     What the return is.
    ///
    pub fn bar(self: TaggedUnionType) bool {
        return switch (self) {
            TaggedUnionType.Int => |i| i != 0,
            TaggedUnionType.Float => |f| f == 0.0,
        };
    }
};

Struct

  • Non-public extern struct
  • Public extern struct
  • Non-public packed struct
  • Public packed struct
  • Non-public normal struct
  • Public normal struct
  • Anything within the namespace of the struct follow the same ordering
  • Doc comment
/// What this struct is
const ExternStruct = extern struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this struct is
pub const ExternStruct2 = extern struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this struct is
const PackedStruct = packed struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this struct is
pub const PackedStruct2 = packed struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this struct is
const Struct = struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN i: i64 - What this parameter is.
    ///     IN f: f64 - What this parameter is.
    ///
    /// Return: Struct
    ///     What the return is.
    ///
    pub fn init(i: i64, f: f64) Struct {
        return Struct {
            .Int = i,
            .Float = f,
        };
    }
};

/// What this struct is
pub const Struct2 = struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN i: i64 - What this parameter is.
    ///     IN f: f64 - What this parameter is.
    ///
    /// Return: Struct
    ///     What the return is.
    ///
    pub fn init(i: i64, f: f64) Struct2 {
        return Struct2 {
            .Int = i,
            .Float = f,
        };
    }
};

Error sets

  • Non-public errors
  • Public errors
  • Doc comment
/// What this error set it
const AllocationError = error {
    /// What this error is
    OutOfMemory,
};

/// What this error set it
pub const AllocationError2 = error {
    /// What this error is
    OutOfMemory2,
};

Global type definitions

  • Non-public user defined types
  • Public user defined types
  • Doc comment
/// What this type is
const NewType = fn () u16;

/// What this type is
pub const AnotherType = TailQueue(u32);

Global Constants

  • Non-public constants
  • Public constants
  • Doc comment
/// What this constant is
const NON_PUB_CONST: u16 = 25;

/// What this constant is
pub const PUB_CONST: i8 = 0;

Global variables

  • Usually global variables should be avoided.
  • Non-public variables
  • Public variables
  • Doc comment
/// What this variable is
var non_pub_var: u16 = 25;

/// What this variable is
pub var pub_var: i8 = 0;

Extern functions

  • No public declarations
  • No doc comments as these would have doc comments where they were defined
extern fn foo() void;

Export Functions

  • No public declarations
  • Doc comment
///
/// What this function does.
///
/// Return: u32
///     What the return is.
///
export fn quux() u32 {
    return 5;
}

Inline functions

  • These shouldn't really be needed as compilers are smart
  • No public declarations
  • Doc comment
///
/// What this function does.
///
/// Arguments:
///     IN i: u32 - What this parameter is.
///
/// Return: u32
///     What the return is.
///
inline fn bar(i: u32) u32 {
    return i + 1;
}

Functions

  • Non-public functions
  • Public functions
  • Doc comment
///
/// What this function does. (Nothing lol)
///
fn baz() void {
    return;
}

///
/// What this function does.
///
/// Arguments:
///     IN comptime T: type - What this parameter is.
///     IN num: T - What this parameter is.
///
/// Return: T
///     What the return is.
///
/// Error: ErrorSet
///     ErrorSet.Error - What the error is.
///
pub fn qux(comptime T: type, num: T) ErrorSet!T {
    if (true) {
        return ErrorSet.Error;
    } else {
        return num;
    }
}

Entry point/init function

  • Only one public declaration
  • Doc comment
///
/// What this function does.
///
pub fn init() void {
    // Set up stuff
}

Unit tests

  • Should be in a testing file
  • The tests should follow the same ordering as the functions being tested
  • Comment throughout the test
  • No doc comment
test "garply" {
    // Set up

    // Pre testing

    // Call function
    garply();

    // Post testing

    // Clean up
}

Run time tests

  • No public functions
  • Prefix rt_
  • Comment throughout the test
  • Doc comment
///
/// What the test tests.
///
fn rt_test1() void {
    // Do a run time test
}

Full example

Showing the full ordering of everything.

  • Imports
    • Zig std imports
    • Non-public user made import
    • Public user made imports
  • Global assembly
  • Enum
    • Non-public extern enum
    • Public extern enum
    • Non-public packed enum
    • Public packed enum
    • Non-public normal enum
    • Public normal enum
  • Union
    • Non-public extern union
    • Public extern union
    • Non-public packed union
    • Public packed union
    • Non-public normal union
    • Public normal union
  • Tagged union
    • Non-public tagged union
    • Public tagged union
  • Struct
    • Non-public extern struct
    • Public extern struct
    • Non-public packed struct
    • Public packed struct
    • Non-public normal struct
    • Public normal struct
  • Error sets
    • Non-public errors
    • Public errors
  • Global type definitions
    • Non-public global types
    • Public global types
  • Global constants
    • Non-public constants
    • Public constants
  • Global variables
    • Non-public variables
    • Public variables
  • Extern functions
  • Export functions
  • Inline functions
  • Functions
    • Non-public functions
    • Public functions
  • Entry point/init function
  • Unit tests
  • Run time tests
const std = @import("std");
const assert = std.debug.assert;

const syscall = @import("syscall.zig");

pub const log = @import("log.zig");

/// What this assembly does
comptime {
    asm (
        \\.global my_func;
        \\.type my_func, @function;
        \\my_func:
        \\  lea (%rdi,%rsi,1),%eax
        \\  retq
    );
}

/// What this enum is.
const ExternEnumType = extern enum {
    /// What A is.
    A,

    /// What B is.
    B,
};

/// What this enum is.
pub const ExternEnumType2 = extern enum {
    /// What A is.
    A,

    /// What B is.
    B,
};

/// What this enum is.
const PackedEnumType = packed enum(u2) {
    /// What A is.
    A,

    /// What B is.
    B,
};

/// What this enum is.
pub const PackedEnumType2 = packed enum(u2) {
    /// What A is.
    A,

    /// What B is.
    B,
};

/// What this enum is.
const EnumType = enum {
    /// What A is.
    A,

    /// What B is.
    B,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN self: EnumType - What this parameter is.
    ///
    /// Return: bool
    ///     What the return is.
    ///
    pub fn foo(self: EnumType) bool {
        return self == EnumType.A;
    }
};

/// What this enum is.
pub const EnumType2 = enum {
    /// What A is.
    A,

    /// What B is.
    B,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN self: EnumType - What this parameter is.
    ///
    /// Return: bool
    ///     What the return is.
    ///
    pub fn foo(self: EnumType2) bool {
        return self == EnumType2.A;
    }
};

/// What this union is.
const ExternUnionType = extern union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
pub const ExternUnionType2 = extern union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
const PackedUnionType = packed union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
pub const PackedUnionType2 = packed union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
const UnionType = union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
pub const UnionType2 = union {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this union is.
const TaggedUnionType = union(enum) {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN self: TaggedUnionType - What this parameter is.
    ///
    /// Return: bool
    ///     What the return is.
    ///
    pub fn bar(self: TaggedUnionType) bool {
        return switch (self) {
            TaggedUnionType.Int => |i| i != 0,
            TaggedUnionType.Float => |f| f == 0.0,
        };
    }
};

/// What this union is.
pub const TaggedUnionType2 = union(enum) {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN self: TaggedUnionType - What this parameter is.
    ///
    /// Return: bool
    ///     What the return is.
    ///
    pub fn bar(self: TaggedUnionType) bool {
        return switch (self) {
            TaggedUnionType.Int => |i| i != 0,
            TaggedUnionType.Float => |f| f == 0.0,
        };
    }
};

/// What this struct is
const ExternStruct = extern struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this struct is
pub const ExternStruct2 = extern struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this struct is
const PackedStruct = packed struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this struct is
pub const PackedStruct2 = packed struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,
};

/// What this struct is
const Struct = struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN i: i64 - What this parameter is.
    ///     IN f: f64 - What this parameter is.
    ///
    /// Return: Struct
    ///     What the return is.
    ///
    pub fn init(i: i64, f: f64) Struct {
        return Struct {
            .Int = i,
            .Float = f,
        };
    }
};

/// What this struct is
pub const Struct2 = struct {
    /// What Int is.
    Int: i64,

    /// What Float is.
    Float: f64,

    ///
    /// What this function does.
    ///
    /// Arguments:
    ///     IN i: i64 - What this parameter is.
    ///     IN f: f64 - What this parameter is.
    ///
    /// Return: Struct
    ///     What the return is.
    ///
    pub fn init(i: i64, f: f64) Struct2 {
        return Struct2 {
            .Int = i,
            .Float = f,
        };
    }
};

/// What this error set it
const AllocationError = error {
    /// What this error is
    OutOfMemory,
};

/// What this error set it
pub const AllocationError2 = error {
    /// What this error is
    OutOfMemory2,
};

/// What this type is
const NewType = fn () u16;

/// What this type is
pub const AnotherType = TailQueue(u32);

/// What this constant is
const NON_PUB_CONST: u16 = 25;

/// What this constant is
pub const PUB_CONST: i8 = 0;

/// What this variable is
var non_pub_var: u16 = 25;

/// What this variable is
pub var pub_var: i8 = 0;

extern fn foo() void;

///
/// What this function does.
///
/// Return: u32
///     What the return is.
///
export fn quux() u32 {
    return 5;
}

///
/// What this function does.
///
/// Arguments:
///     IN i: u32 - What this parameter is.
///
/// Return: u32
///     What the return is.
///
inline fn bar(i: u32) u32 {
    return i + 1;
}

///
/// What this function does. (Nothing lol)
///
fn baz() void {
    return;
}

///
/// What this function does.
///
/// Arguments:
///     IN comptime T: type - What this parameter is.
///     IN num: T - What this parameter is.
///
/// Return: T
///     What the return is.
///
/// Error: ErrorSet
///     ErrorSet.Error - What the error is.
///
pub fn qux(comptime T: type, num: T) ErrorSet!T {
    if (true) {
        return ErrorSet.Error;
    } else {
        return num;
    }
}

///
/// What this function does.
///
pub fn init() void {
    // Set up stuff
}

test "garply" {
    // Set up

    // Pre testing

    // Call function
    garply();

    // Post testing

    // Clean up
}

///
/// What the test tests.
///
fn rt_test1() void {
    // Do a run time test
}