-
Notifications
You must be signed in to change notification settings - Fork 3
Coding style
JR edited this page Jan 26, 2022
·
6 revisions
Due to the number of developers the coding style is generally consistent, changing slightly over time. These are the recommended guidelines.
The closest we can get with dfmt
:
$ dfmt --split_operator_at_line_end=true --space_after_cast=false --compact_labeled_statements=false --template_constraint_style=always_newline -i
// functionName (for grepping)
/++
Brief introduction to what the plugin does.
Brief explanation how it does it.
Example:
---
// three dashes before and after
---
Params:
templateParam = Description as if runtime param. Long lines
are wrapped and indented.
variableName = Description, wrap at ~80 columns.
secondVariable = Description, same.
thirdVariableIndented = Same.
Returns:
A humanly-readable explanation of what the resulting value
represents, potentially with concrete examples.
See_Also:
[adrdoxNativeLink]
[rarelySeeThis]
+/
@(IRCEventHandler()
.onEvent(IRCEvent.Type.ANY)
.chainable(true)
.verbose(true)
.addCommand(
IRCEventHandler.Command()
.word("word")
.policy(PrefixPolicy.prefixed)
)
)
void functionName(templateParam, T)(T variableName, T secondVariable,
T thirdVariableIndented) // @safe inferred, only add if we need the guarantee
if (someConstraint!T && ownUnindentedLine!T)
{
import generally.early : onlyFunctionsBeingUsed, nothingElse;
if (((a == b) && (c == d)) || (e == f))
{
// ...
}
if (g == h) return T.init; // only if it fits on one line
// Don't do this, vulnerable to OpenSSH mistakes
/*if (i == j)
return T.init;
*/
// This is discouraged but okay, prefer using {} for the main if case. else *always* with {}
if (k == l) return T.min;
else
{
return T.max;
}
// In this case, better yet;
return (k == l) ? T.min : T.max;
import stuff.things : functionOnlyUsedHere;
functionOnlyUsedHere();
immutable someLocal = cast(double)someInt; // double inferred
with (SomeEnum)
final switch (someEnumValue)
{
case firstMember:
// cases on same indentation as the switch statement
break;
case secondMember;
// ...
break;
/*default:
// In non-final switches, defaults have breaks
break;*/
}
immutable someString = getSomeString();
if (!someString.length) return; // use .length to test if "" or null
// someString.writeln; // Use normal writeln(...) or *at least* .writeln();
foreach (immutable i; 0..100_000)
{
// Prefer this to for (int i; i<100_000; i++)
// If you really need normal for, use size_t i and ++i
// immutable index. Underscores where commas would be
if (!condition) break;
// Normal path
}
}
///
unittest
{
// ...
}
- British English, to prove a point.
- Put
{
and}
on their own lines. - Very soft 80 column, hard 120 column wraps.
- Try to write testable code whenever possible, place a unittest immediately after the function.
- Always* enclose expressions between parantheses;
if (((a == b) && (c == d)) || (e == f)) { /* ... */ }
-
if
statements don't need{}
brackets iff it can fit on one line, and there is noelse
case. -
else
always needs{}
brackets, always. - Names may be long; avoid
p
orupr
except forsize_t
indexes. - No need for
g_
,m_
ands_
prefixes. - functions (and function templates) camelCase.
- Types, other templates and mixins PascalCase.
-
enum
s PascalCase,enum
members camelCase. - Constants camelCase, no C-style UPPERCASE_CONSTANTS;
-
/++ ... +/
for documentation;//
,/* */
,/+ +/
for comments./+
can nest/*
so may be preferred in some cases. - Return early, avoid extra indentation.
-
immutable
whenever possible,const
when not. Only use mutable types if it's a range that requiresauto
, or it's a variable that we want to reuse (like string verbs). -
static immutable
andenum
whenever possible, except in such cases where the manifest constant-ness of them would cause unecessary allocations. -
final class
preferred whenever possible. -
goto
only between cases in aswitch
.
- Use UFCS, but only where it makes sense.
- Keep all state inside the plugin class. This ensures that everything is reset on reconnections.
- Initialise resources in
initResources
but generally populate non-JSON arrays afterRPL_WELCOME
or after MOTD. - Use either a timed Fiber/delegate or
PING
to automate tasks. - Take
IRCEvent
s byconst ref
to minimise the copies made.
- Regex is convenient but super bad for compile times. Avoid.
- Avoid using
.to!string
or.text
on largeenum
s (read:IRCEvent.Type
) like the plague. Usekameloso.conv.Enum
. -
with
statements in great moderation, but freely when it's forenum
s. - Templates are great, but don't be afraid to write normal functions.
- Don't go overboard with annotations unless it's a library-type function.
- When a function template is a frontend to another template that does all the work, the former is
foo
and the latter isfooImpl
.