Skip to content

Draft: New Coding Standards

Pieter-Jan Briers edited this page Mar 19, 2017 · 10 revisions

/vg/station coding standards

Non-final

Some parts of the standards are non-final, and do not have to be followed. Updates to the standards will be announced to contributors using Discord and the IRC. Non-final sections are subtitled as such.

Object definitions

All paths should be absolute, up to variable definitions: BYOND permits relative pathing, however this is worse for readability and make searching for specific procs or variables much harder.

An example of relative pathing:

obj
    machinery
        apc
            var
                on = TRUE

            attackby()
                ...

            proc
                off()
                    ...

The same example, but then absolutely pathed:

/obj/machinery/apc
    var/on = TRUE

/obj/machinery/apc/attackby()
    ...

/obj/machinery/apc/proc/off()
    ...

Variables and procs

Language

All proc and variable names should be in American English, this is to be consistent with BYOND which also uses American English (variables like color, for example). This includes s/z differences.

Types and casting

The runtime operator : is never permitted for accessing vars or procs on a variable, even if preceeded by a typecheck. You should always cast to the proper type after the typecheck, and then access vars and procs normally, using ..

Variable definitions.

All variable definitions should use the most specific path possible: This: var/obj/A is worse than var/obj/machinery/A when the code only expects a machine.

Constant variables (/const) should never be used, use #defines instead.

When making a variable a list which contains only a single type of object, the variable type should correctly represent this. (var/list/obj/machinery/machines vs var/list/machines)

Proc variables

While defining variables in procs with the same name as variables on the src object is allowed, this should not be done because it makes the code harder to read and understand.

Parameters

While using var/ is optional in proc parameters, it should be used anyways. The rules for var typing also apply to proc parameters: types should be as specific as possible.

For ellipses (procs which take any amount of arguments), one should use ... in the proc parameters like this: /proc/myproc(...)

Values

Numbers

When SS13 was initially decompiled, the decompiler used made all integer numbers end in .0 due to a bug. This has blindly been taken over by oldcode and is prevalent around the code. Integers should never end in .0.

Booleans

When a value should only be used as a boolean, the native TRUE and FALSE macros should be used instead of the more common 1 and 0, respectively.

Defines: magic numbers and bare strings

All values which appear in code repeatedly and have to be the same in every instance should be replaced instead with a string or number define.

/obj/item/stamp
    var/stamp_stage = 0

/obj/item/stamp/proc/stamp()
    if(stamp_stage == 0)
        stamp_stage = 2

Should instead be

#define UNSTAMPED    0
#define STAMPED      2

/obj/item/stamp
    var/stamp_stage = UNSTAMPED

/obj/item/stamp/proc/stamp()
    if(stamp_stage == UNSTAMPED)
        stamp_stage = STAMPED

World and access

'in world' should always be avoided. Any requirement to loop through all objects fulfilling a criteria in the world should be done by a global list which objects add themselves to and remove themselves from.

Accessing global variables should use global. to make it more clear that the variable is global.

You should never use src. when accessing variables or procs on the src object, as it is always implied, unless there is a code reason, such as variable ambiguity.

Formatting

All statements, conditionals, and loops should be on their own lines. Especially long conditionals should be broken up by the \ separator and put onto multiple lines for readability. A good guide is no more than 4 conditional statements per line.

No usage of labels and goto. Labelled loops are also forbidden.

Indentation & alignment

You should try to avoid indenting code as much as possible. This is bad:

/obj/myobject/attackby(var/obj/item/W, var/mob/user)
    if (istype(W, /obj/item/device/multitool))
        thing()
    else
        otherthing()

This is better:

/obj/myobject/attackby(var/obj/item/W, var/mob/user)
    if (istype(W, /obj/item/device/multitool))
        thing()
        return
    otherthing()

All indentation should be done by hard tabs. This means the tab character should be used, not 4 spaces.

Spacing

There should be a space between all binary (=, ==, <(=), >(=), !=) and trinary (?:) operators and their operands. There should not be a spacing between unary operators (!, ~, ++, --) and their operands. Note that this rule can be overruled in the case where it improves readability, especially with operator precedence:

var/x = a*b + a*c

Code should be manually aligned if it improves readability. However it should be aligned with spaces in this case, to prevent the alignment breaking on different tab sizes. This only applies to decorative alignment: indentation is done by tabs as above.

Line terminators

While the semicolon is a legal line terminator for DM, it is entirely redundant. Lines should not end with a semicolon.

Proc usage

You should always use helper procs or macros instead of writing code from scratch. This improves maintainability a ton.

Systems and structure

Object-oriented programming

All systems and implementations should strive to be designed with Byond's object-oriented language in mind. The following things should be avoided:

  • Type lists and hard-coded type checking for behaviour in general systems

  • Type checks on src - this is a clear sign you've gone wrong