Conventions

This document expands on the Style guide to elaborate on some informal conventions used in the Hare community.

Recommendations for function names

Note

See Conventions for foreign symbol names for information on naming Hare symbols after foreign symbols like those defined by system libraries.

To name a function, first identify its purpose. If you were to describe this purpose in a sentence, you should be able to identify up to three grammatical items of importance: the verb, the object, and the subject. The subject is usually the actor, the object is usually being acted upon, and the verb defines the action being taken.

When naming a Hare function, use the format “subject_verbobject”, where the subject preceeds the verb and object, separated by an underscore, and the object directly follows the verb. If you can infer the subject or object from context, they may be omitted, so “verbobject”, “subject_verb”, or simply “verb” may be appropriate names.

In the sentence “Sam goes to the store”, “Sam” is the subject, “store” is the object, and “go” is the verb. The equivalent function name would be “sam_gostore”. If we have additional context, for example if this is in the “sam” module, we could call it “sam::gostore”. Or perhaps the object is given by a parameter, in which case “go” is sufficient:

fn sam::go(to: destination) void;

Abbreviating terms is acceptable, such as “str” for “string” or “tok” for “token”.

This approach prefers terseness when unambiguous. Here are some real-world examples:

fn bufio::scantok(stream: *io::stream, delim: u8) ([]u8 | io::EOF | io::error);

fn io::read(stream: *io::stream, buf: []u8) (size | io::EOF | io::error);

fn lex::init(in: *io::stream, path: str) lexer;

Note the arrangement of parameters: the object being acted upon comes first. For example, if you have “source” and “destination” parameters, “destination” should be placed first in the parameter list.

Verbs for allocation strategies

It is useful to communicate the allocation strategy in function names, to lend readability to the implications for Hare’s manual memory management system. The following conventions are recommended.

For functions which initialize a value and return it, either via allocation or via the stack, name these functions after the object being initialized. For example, to initialize a SHA-256 hash, you use crypto::sha256::sha256(). If a more specific verb than “allocate” or “initialize” would be appropriate, name the function after that verb. For example, “open” or “connect” may be more appropriate names than “file” or “client”.

If a function accepts a pointer to a value as a parameter, and will initialize that value, use the “init” verb to name the function.

For functions which free resources associated with an object, if the object itself is freed, use the verb “free”. If the object itself is not freed, but some other state associated with it, use the verb “finish”.

Recommendations for documentation

Consult man haredoc for technical details regarding documenting Hare interfaces through comments in the source code.

It is useful to have some linguistic conventions for inline documentation. The following guidelines provide such conventions for any programs which wish to be consistent with the rest of the Hare ecosystem in their approach to API documentation.

All programmer-facing documentation should be written in English, and all public (exported) members should be documented. Not documenting an exported member signals that it is not designed to be used by third-party programs.

Your documentation should be as concise or as long as is necessary. Programmers reading the reference documentation are usually in a hurry, but they also appreciate comprehensive explanations. Aim to be as short as possible without omitting necessary details.

Include a period after the last sentence.

Function documentation should complete the following thought: “This function [does, will, is used to]…”. Examples:

  • “Insert a new entry into the list”

  • “Parse the next record from the file”

Type documentation should complete the following thought: “This type is…” or “This type $verbs…”. Examples:

  • “An error indicating that an invalid sequence was encountered”

  • “Indicates that more data is required to finish processing”

  • “Stores the state for an XML parser”

Constant documentation should complete the following thought: “This constant is…”

  • “The size, in bytes, of an MD5 digest”

  • “The magic string identifying a PNG file”

Recommendations for errors

These recommendations cover programmer-facing errors. User-facing errors have different concerns, for example they may require internationalization.

Each module should provide an error type which is a tagged union of all possible errors which might be returned by functions in that module, and an strerror function which explains the error as a string. These strings should be written with “Sentence case” and should not end with a period. It should also be written so that it makes sense when passed to fmt::fatal("Error:", example::strerror(err)).

Write programmer-facing error messages in English. This includes the return value from strerror, and also the error messages used in abort and assert expressions.

Conventions for foreign symbol names

When writing Hare symbols whose names are more authoritatively specified elsewhere, different conventions apply, such as in the following scenarios:

  • Forward-declaring symbols defined by a system library, e.g. SDL_Init

  • Naming symbols after well-known constants, e.g. x86_64 register names

  • Naming symbols that reference names defined by a specification, e.g. EFI_FILE_PROTOCOL

In this case the convention is to use the naming scheme defined by the more authoritative source, ignoring Hare’s normal naming and case conventions for those symbols. For example, SDL_Init should not be renamed to the more idiomatic Hare convention of sdl_init.

However, you MAY make the following changes:

  • Removing a namespace suffix which is more adequately represented by a Hare namespace, e.g. SDL_Init becomes sdl::Init (note “I” remains capitalized).

  • Removing Hungarian notation prefixes, particularly for C enums, e.g. SDL_BLENDFACTOR_ZERO is a member of enum SDL_BlendFactor and can simply be called ZERO if placed into a Hare type called sdl::BlendFactor.