Stream: brlcad

Topic: The Elements of Style


view this post on Zulip Daniel Rossberg (Jul 13 2025 at 19:22):

Preface

There was a discussion on GitHub regarding a programming style guide for arbalest. There is the HACKING in the brlcad repository, of course, but I don't think it is suited for modern C++ code. And, I hate especially the indentation rules.

The following represent very much what I used for the development of MOOSE, still they shall not be understood as a proposal for an arbalest style-guide. Rather, I want to demonstrate my expactations regarding a coding style guide. You may observe many issues among my set of rules. But I hope that they can serve as the starting point of a serious discussion.

view this post on Zulip Daniel Rossberg (Jul 13 2025 at 19:24):

Basic principles

view this post on Zulip Daniel Rossberg (Jul 13 2025 at 19:34):

Style Guide

Source Code Layout

There shall be no more than one statement per line.

Source Code File

Every source file begins with the copyright notice, license, and a short description.
Example:

/*                    V E C T O R L I S T. C P P
 * BRL-CAD
 *
 * Copyright (c) 2020-2025 United States Government as represented by
 * the U.S. Army Research Laboratory.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this file; see the file named COPYING for more
 * information.
 */
/** @file VectorList.cpp
 *
 *  BRL-CAD core C++ interface:
 *      vlist implementation
 */

Header files shall be protected against multiple including with a define of the form <NAMESPACE>_<FILENAME>_INCLUDED.
Example:

/*                    V E C T O R L I S T. H
 * BRL-CAD
 *
 * Copyright (c) 2020-2025 United States Government as represented by
 * the U.S. Army Research Laboratory.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this file; see the file named COPYING for more
 * information.
 */
/** @file VectorList.h
 *
 *  BRL-CAD core C++ interface:
 *      vlist declaration
 */

#ifndef BRLCAD_VECTORLIST_INCLUDED
#define BRLCAD_VECTORLIST_INCLUDED

[includes]
[forward declarations]

namespace BRLCAD {

[declarations]

}


#endif // BRLCAD_VECTORLIST_INCLUDED

Version information are stored in the version control system, and only there.

Indents

A single indent consists of 4 white-spaces.
Deeper indentations consist of a multiple of that.

Tabs may not be used for the source code layout.

Operators

Except for unary operators, there shall be at least one white-space before and after it.

Same operators shall be written below each other.
Example:

a   = 7;
b   = 6;
ab  = 5;
cd += 4;

Unary operators are written without space between the operand.
Example:

++i;

Blocks

Opening brackets shall be in the line preceding the block.
Example 1:

int FunctionName(void) {

Example 2:

for (size_t i = 0; i < 256; ++i) {

The content of a block has a single indent.
Example:

int FunctionName(void) {
    int ret = 0;

    return ret;
}

Closing brackets shall be in an own line.

Preceding a block, there shall be an empty line, except, the block follows immediately the beginning of another block.
Example 1:

int a = 7;

for (size_t i = 0; i < a; ++i) {

Example 2:

int FunctionName(void) {
    for (size_t i = 0; i < 256; ++i) {

Following a block, there shall be an empty line, except, it follows immediately the end of another block or the block's preceding statement is continued.
Example 1:

    int a = 7;
}

b = 6;

Example 2:

        int a = 7;
    }
}

Example 3:

if (a == 7) {
    b = 6;
    c = 5;
}
else
    b = 0;

Function declarations

The parameters of a non-member function shall be written as a block. The opening bracket goes into an own line.
Example:

int FunctionName
(
    int    number,
    double value
) {

This rule holds for declarations in header files as well as function implementations. This accentuates the impotence of the parameters of a function. They are easier to understand.

The parameters of class methods shall be written below each other, the first one in the same line as the function name.
Example:

class ClassName {
public:
    int FunctionName(int    number,
                     double value);
};

Often, classes have many methods with similar signature. A compact style eases the overview.

The declaration of a parameterless function shall be written in a single line.
Example:

int FunctionName(void) {

Keyword Names

Keywords, which will handed over to the compiler, shall be written in camel-case.
Example:

int ExampleFunction(void) {
    int exampleVariable = 7;

    return exampleVariable;
}

Keywords, which are handled by the preprocessor, shall be written in capital letters.
Example:

#define MAX_USER_NUMBER 4

Names of objects with fixed address start with a capital letter, objects with variable address start with a lower letter.

Function and type names start with a capital letter.

Variable names start with a lower letter.

Constants names start with a capital letter.

Variables, which are not declared in the function, where they are used, have an underline "_" in the name.

Variables, which are members of a class, start with "m_".
Example:

class ExampleClass {
public:
    int& ExampleFunction(void) {
        return m_exampleVariable;
    }

private:
    int m_exampleVariable;
};

Programming Style

Variables

A variable declaration shall be its initialization too, or a variable shall be declared not until a value can be assigned.

A convincing name shall be preferred to comments.
Bad:

size_t i = 0; // number of elements

Good:

size_t numberOfElements = 0;

This means more typing, but if somebody reads the code, e.g. hits this variable in a debugger, they see immediately what it is. No need to scroll back. The variable names are not for the compiler, it can handle "gt5jd7" as well, but for the programmers.

Functions

Functions have exactly one exit point (return statement).
This makes it easier to follow all processing paths, because they all end at the single exit point. In addition, it makes it easier to debug a function, because there is exactly one place for a break point at the function's end.
Example:

int Foo(
    int* value
) {
    int ret = 0;

    if (value != nullptr)
        ret = *value;

    return ret;
}

goto statements

goto statements are generally deprecated.

The usage of goto statements can be justified.
For example in exception handling:

bool OpenFile(
    const char* fileName
) {
    bool ret = false;

    try {
        if (!Exist(fileName))
            throw 1;

        if (!ReadingPermitted(fileName))
            throw 1;

        if (!FileHandleAvailable(fileName))
            throw 1;

        // open file
        ret = true;
    }
    catch(int i) {}

    return ret;
}

Here, the throw of an exception is used to jump out of the file processing. But, an exception isn't a simple jump but a much more complicated mechanism. In such a case, using goto statements can be a solution:

bool OpenFile(
    const char* fileName
) {
    bool ret = false;

    if (!Exist(fileName))
        goto EXIT_LABEL;

    if (!ReadingPermitted(fileName))
        goto EXIT_LABEL;

    if (!FileHandleAvailable(fileName))
        goto EXIT_LABEL;

    // open file
    ret = true;

EXIT_LABEL:
    return ret;
}

See also recommendation 2 in section 14.11 of Bjarne Stroustrup's "The C++ Programming Language".

view this post on Zulip Erik (Jul 16 2025 at 23:17):

adapting an existing style that something like astyle or vs code natively supports might be best

view this post on Zulip Daniel Rossberg (Jul 17 2025 at 19:39):

I'm not sure what you have in mind. It should be feasible by humans with an ordinary editor to follow the rules. E.g., I use Notepad++ or Kate. But with these, it's very hard to do the indentation in brlcad right. If a special software is necessary to do follow a rule, it would be a red flag for me.

view this post on Zulip Sean (Jul 22 2025 at 07:39):

Current indentation style in BRL-CAD is a legacy exception, and I think we all agree'd long ago to abandon it. Just a matter of timing to flip the style switch as it will invalidate all outstanding patches and pull requests...

I'd hope we (as a team) could spend a month or two integrating and closing out as many as possible before doing a wholesale style change.

I actually see no major issues myself with the style guide and examples above (for arbalest or otherwise). Very much a C++ style I think as some constructs don't extend well to C-only code. Only thing that even jumped out was perhaps preferring a more concise preprocessor header inclusion protections, starting everything in uppercase, and not really liking parameter blocks unless we're documenting them right there. I generally want as many lines of code to fit on my screen as possible so long as it doesn't violate one-thing-per line (with params not being a thing, the decl is the thing). Towards that end, the orphaned else is another oddity that just adds lines imho, but I could probably get used to it.

view this post on Zulip Sean (Jul 22 2025 at 08:18):

if it weren't for that, what's described is highly similar to the K&R one true brace style (1TBS) and Qt/KDE style guide (though you disagree more there on some points).

Here's the built-in styles supported by clang-format and astyle respectively:

LLVM (the default), GoogleChromiumMozillaWebKitMicrosoftGNU 

allman / bsd / breakjava / attachkr / k&r / k/rstroustrupwhitesmithvtkratliff / bannergnulinux / knfhorstmann / run‑in1tbs / otbsgooglemozillawebkitpicolisp

What you described, aside from the three things that jumped out to me (as nobody does those afaikt), is very similar to the WebKit style (except opening brace) and LLVM style (except indent).

view this post on Zulip Daniel Rossberg (Jul 25 2025 at 15:35):

...according to my first "basic principle".

The second says: "The code should be compact, as long as it doesn't hinder its legibility." An important use case is the fast scrolling through a source file. The beginning of functions are emphasized, including their parameter lists, because that's the most important information about functions. This is, what e.g. doxygen extracts for documentation. It shall be recognizable by scrolling by. Some of the other rules shall support the fast scrolling too.


Last updated: Aug 07 2025 at 01:01 UTC