Skip to content

BTW Code Style Guide

Abigail Moore edited this page Sep 16, 2022 · 13 revisions

This marks the code style for new contributions to BTW. It is recommended that addons for BTW also follow this code style.

1 Source File Structure

A source file consists of, in order:

  1. License or copyright information, if present
  2. Package statement
  3. Import statements
  4. Exactly one top-level class

Exactly one blank line separates each section that is present.

2 Formatting

2.1 Braces

Braces are used with if, else, for, do, and while statements, even when the body is empty or contains only a single statement.

2.2 Non-empty Blocks

Brace placement around non-empty blocks should follow the Stroustrup Variation of Kernighan & Richie Style, which can be found here:

  • No line break before the opening brace
    • Exception: line-wrapped block openings should have a line break before the opening brace.
  • Line break after the opening brace
  • Line break before the closing brace
  • Line break after the closing brace
  • A single blank line after the closing brace, unless the closing brace is the middle of a compound block (e.g. if/else)

Example:

return () -> {
    while (condition()) {
        method();
    }
};

return new MyClass() {
    @Override public void method() {
        if (condition()) {
            try {
                something();
            }
            catch (ProblemException e) {
                recover();
            }
        }
        else if (otherCondition()) {
            somethingElse();
        }
        else {
            lastThing();
        }
    }
};

if (int foo == 0 &&
        int bar == 0)
{
    doSomething();
}

2.3 Empty Blocks

Empty blocks may follow Stroustrup style as detailed above, or may be closed immediately after it is opened with no character or line break between the opening and closing braces.

The exception to this is if it is part of a multi-block statement such as if/else or try/catch/finally, in which case it must follow Stroustrup style.

2.4 Indentation

Each time a new block or block-like construct is opened, indentation increases by 1 tab. Do not use spaces for indentation.

2.5 One Statement Per Line

Each statement is followed by a line break. Do not put multiple statements on a single line.

2.6 Column Limit: 160

Columns are limited to 160 characters. Except for the exceptions listed below, any line which would exceed this limit must be line-wrapped.

Exceptions:

  • Lines where a break would be impossible or unreasonable.
  • Package and import declarations

2.7 Line-Wrapping

When code that might otherwise legally occupy a single line is divided into multiple lines, this activity is called line-wrapping.

2.8 Where to Break

  • If the line break is performed at an operator, the break comes after the operator.
  • If the line break is performed at a dot separator, the break comes before the "."
  • A method or constructor stays attached to the parenthesis "(" that follows it.
  • A comma "," stays attached to the token that preceded it.
  • When line wrapping, a closing brace or parenthesis stays attached to the token which preceded it.

2.9 Grouping Wrapped Arguments

If a method is line-wrapped to multiple lines, the arguments should be grouped as is logical. For example, coordinates should be kept together unless the group is long enough to itself be line-wrapped.

2.10 Indentation

Each continuation line is indented by 2 tabs.

3 Whitespace

3.1 Vertical Whitespace

A single blank line always appears:

  • Between consecutive members or initializers of a class: fields, constructors, methods, nested classes, static initializers, and instance initializers.
    • Exception: Blank lines between two consecutive fields are optional. Blank lines may be used to create logical groupings.
  • As otherwise required by this document.

A single blank line may also be included anywhere it improves readability, such as by grouping statements into logical subsections.

A blank line before the first member or initializer, or after the last method or initializer, is discouraged.

Multiple consecutive blank lines are discouraged.

3.2 Horizontal Whitespace

Beyond where required by the language or other style rules, and apart from literals, comments and Javadoc, a single ASCII space also appears in the following places only:

  • Separating any reserved word such as if, for, or catch, from an open parenthesis "(" that follows it on that line.
  • Before any opening brace "{".
  • On both sides or a binary or ternary operator.
  • After ,:; or the closing parenthesis ")" of a cast.
  • Between the type and variable of a declaration: List<String> list
  • On both sides of a varargs declaration: Object ... varargs

A space after the "//" preceding a single line comment is allowed but not required.

Space between parenthesis or braces and the inner contents is not allowed e.g. foo( x )

Trailing whitespace is not allowed.

4 Specific Constructs

4.1 Enum classes

Each entry to an enum is always follwoed by a line break. An additional single blank line is also allowed.

4.2 Variable Declarations

4.2.1 One Variable per declaration

Each variable declaration line only declares a single variable.

  • Exception: Block or Item prototype fields may be grouped due to the large number of them which may be present.

4.2.2 Local Variables Declared When Needed

Local variables are declared close to where they are first used (within reason) to minimize scope. They are not to be declared at the top of the block they are contained in.

4.3 Arrays

4.3.1 Block-Like Initializers

Array initializers can optionally be block-like, in which case brace convention follows that of non-empty blocks stated above.

The following are all valid:

new int[] {
    1,
    2,
    3,
    4
};

new int[] {
    1, 2,
    3, 4
};

new int[] {
    1, 2, 3, 4
};

4.3.2 No C-style Array Declarations

The square brackets form a part of the type, not the variable: String[] args, not String args[].

4.4 Switch Statements

4.4.1 Indentation and Whitespace

As with any other block, the contents of a case statement are indented by 1 tab. However, case and default statements may be placed at the same level of indentation as the switch statement.

Case and default statements should be placed on their own lines. No additional blank lines are present before or after each case.

4.5 Annotations

Annotations applying to a class, method, or constructor appear immediately before the declaration, with a line break after each annotation.

Annotation applying to a field may appear each on the same line, but a line break follows the last annotation.

4.6 Comments

Comments should be preceded by a single blank line, and should not have any blank lines following them.

4.7 Modifiers

Class and member modifiers, when present, appear in the order recommended by the Java Language Specification:

public protected private abstract default static final transient volatile synchronized native strictfp

4.8 Numeric Literals

Numeric literals, if present, always use capital letters to denote their type e.g. 1.5F or 300000000L

5 Class Segmentation

A large class may be segmented into logical blocks for improved readability.

These blocks should be separated by a double slash "//" followed by six dashes "------", a space, the header name, a space, six more dashes, and another double slash. Further hierarchical divisions may be created by increasing the number of dashes used (e.g. from six to twelve).

Fields should always be declared at the top of the segment they belong to.

6 Naming

6.1 Rules Common to All Identifiers

Identifiers use only ASCII letters and digits, and, in a small number of cases noted below, underscores.

6.1.1 Prefixes

Use of Hungarian notation or any other prefixes is not allowed. For example, do not prefix variables with their type, and do not use m_ to denote fields.

6.1.2 Camel Case

When converting a phrase into camel case, acronyms should be treated as a single letter. If a name in lower camel case begins with an acronym, the acronym should be all lowercase. Otherwise the acronym should be all uppercase.

6.2 Rules by Identifier Type

6.2.1 Package Names

Package names are all lowercase, with no underscores.

6.2.2 Class Names

Class names are written in UpperCamelCase

6.2.3 Method Names

Methods are named using lowerCamelCase. They do not begin with a capital letter, and do not use underscores, with the following expcetion:

  • A private variant of a public method which contains the actual logic (with the public method handling translation to the private method) may use the suffix _do

6.2.4 Constant Names

Constant names use CONSTANT_CASE.

A constant is any static final field which is immutable and whose methods have no side-effects. If any part of the instance's observable state can change, then it is not a constant.

6.2.5 Non-Constant Field Names

Non-constant field names use lowerCamelCase.

6.2.6 Parameter Names

Parameter names use lowerCamelCase.

6.2.7 Local Variable Names

Local variables use lowerCamelCase.

Even when final and immutable, local variables are not considered constants and should not be styled as such.

6.3 Conventions

6.3.1 Package Names

Packages are to use only lowercase letters in their names, and should generally use singular nouns as names, e.g. btw.block.tileentity.

When creating a package to hold a collection of similar objects, such as Block or Item definitions, the package name may be plural, e.g. btw.item.items.

Exceptions to the package naming conventions may also be made if it would increase clarity.

6.3.2 Class Names

Class names are to use conversational order as much as possible e.g. RoughStoneBlock instead of BlockStoneRough. Exception to this may be made when grouping classes together, e.g. BucketBlockWater and BucketBlockLava, in which case either style is allowed.

Enums and interfaces should not be preceded by any prefixes such as "I" or "Enum".

6.3.3 Boolean Getters and Setters

Boolean getters and setters should be preceded by is (or another question such as has) and set, respectively.

Example:

public boolean isFoo() {
    return foo;
}

public void setFoo(boolean foo) {
    this.foo = foo;
}

Do not use getIs or setIs for boolean getters or setters.

6.3.4 Variable Names

Single character field, parameter, or local variable names should not be used, except in the case of immediately obvious names such as x, y, and z for coordinates.

Do not prefix temp variables with "temp" unless omitting the prefix would cause ambiguity. Even in such cases, this practice is discouraged and other naming conventions should be used.

6.3.5 Coordinates

x, y, and z should be used for coordinates. i, j, and k should not be used except as local coordinates with respect to x, y, and z.

More specific coordinate names should have the coordinate at the end of the name. e.g. velocityX not xVelocity

7 Programming Practices

7.1 @Override

Always use @Override wherever it is legal.

7.2 Static Members

Static members should always be qualified using the class. Never use an instance to refer to a static member.

7.3 Caught Exceptions

it is very rarely correct to do nothing in response to a caught exception. (Typical responses are to log it, or if it is considered "impossible", rethrow it as an AssertionError.)

When it truly is appropriate to take no action whatsoever in a catch block, the reason this is justified is explained in a comment.

Clone this wiki locally