標準ライブラリスタイルガイド Standard Library Style Guide
著者: Clay Sweetser, Dominik Picheta
バージョン: 0.18.0
導入 Introduction
Nimが多様なコードや書式の書き方に対応しているとはいえ、一定範囲内のコミュニティーの成果物(例えば標準ライブラリなど)が必要に応じてひとつの一貫したスタイルガイドラインに従っている、というのはやはり有益なのである。
この拡張提案の目標は、標準ライブラリが従うべき一連のガイドラインを書き出すことである。
このルールには例外があることを覚えておいてほしい。Nimは柔軟であり、特定の文脈においてはこのスタイルガイドの一部が理にかなわない時がある。加えて、Pythonのスタイルガイドが時間とともに変わるように、このスタイルガイドも変わる。
これらのルールが強く推奨されるのは、Nimのコードベースや公式プロジェクト(たとえば、Nimコンパイラー、標準ライブラリ、C2Nimなどの公式ツールなど)のコントリビューターのみである。
スペーシングとホワイトスペースの規則 Spacing and Whitespace Conventions
- 1行は80文字以上長くなってはいけない。各行に書かれる情報を制限すると、コードの可読性が上がる—読者はより小さい塊を処理できる。
- ブロックのインデントにはスペース2個を使うべきである。タブストップは禁止されている(コンパイラがこれを強制している)。スペースを使うということは、コードの見た目がエディター間でより統一されることである。スペースとは異なり、タブストップの幅はエディター間で異なり、全てのエディターにその幅が変更する方法があるとは限らない。
- このガイドで推奨されているもの以外のスタイル上の理由でホワイトスペースを使うことは許されているが、その実践においては十分な注意が必要である。全てのエディターが自動的なコード揃えに対応している訳ではなく、長いコードを手作業で再整理するのはすぐに面倒くさくなる。
# これはよくない。というのも次に誰かが来て
# このコードブロックを編集しようとしたとき、彼らは
# 全ての代入文を再整理しなくてはいけない。
type
WordBool* = int16
CalType* = int
... # 5行後
CalId* = int
LongLong* = int64
LongLongPtr* = ptr LongLong
命名規則 Naming Conventions
注意:下にまとめてある規則は現在の命名規則であるが、これらの規則は常にこうだった訳でない。
以前、識別子の命名規則は、その識別子のベースタイプを示すPascalの慣例的な接頭辞に従っていた。PFooがポインタや参照型、TFooが値型、EFooが例外、などである。
これはその後変更されたが、標準ライブラリの中でこの規則を使っているところが多くある。
このスタイルが残っているのは、それがただ単に遺産であるためであり、将来的には変更される。
- 型の識別子はパスカルケース(PascalCase)を使うべきである。そのほかの識別子はキャメルケース(camelCase)を使うべきであり、例外として定数にパスカルケースを使ってもよいが要求はされない。
# 定数は大文字で始まっても小文字で始まってもよい
const aConstant = 42
const FooBar = 4.2
var aVariable = "Meep" # 変数は小文字で始まらなくてはならない
# 型は大文字で始まらなくてはならない
type
FooBar = object
C/C++のラッパーからくる定数には、すべて大文字(ALL_UPPERCASE)を使ってもよいが、美しくない。(なぜCONSTANTと叫ぶ必要があるのだ。定数は悪さをせず、するのは変数なのに)
- 値、ポインタ、レファレンスの亜種を持つ型を名付けるときは、最もよく使うものに通常の名前を付けて、そのほかのものに"Obj"や"Ref"、"Ptr"といった接尾辞をつけるとよい。もしも、最もよく使われるものが一つに定まらないのであれば、接尾辞をポインタの識別子にのみ付けるとよい。C/C++のラッパーも同様である。
type
Handle = object # もっともよく使われる
fd: int64
HandleRef = ref Handle # より少なく使われる
- 例外やエラー型は"Error"接尾辞を持つべきである。
type
UnluckyError = object of Exception
- *{.pure.}*プラグマを記されていない限り、enumsの要素は識別に使える接頭辞(例えばenumの名前の省略など)を持つべきである。
type
PathComponent = enum
pcDir
pcLinkToDir
pcFile
pcLinkToFile
- 純粋でないenumの値はcamelCaseを使うべきであり、純粋なenumの値はPascalCaseを使うべきである。
type
PathComponent {.pure.} = enum
Dir
LinkToDir
File
LinkToFile
- HTTP、HTML、FTP、TCP、IP、UTF、WWWの時代において、これらのすべて大文字でなくてはならない特殊な単語である、というフリをして、現実の単語として扱わないのは愚かである。つまり、
parseURL
よりもむしろparseUrl
であり、checkHTTPHeader
よりもむしろcheckHttpHeader
である。
コーディング規則
'return'文は理想的には、その制御的な性質が要求されるときに使われるべきである。関数で暗示的に宣言された'result'変数を可能な時はいつも使うべきである。これは可読性を高める。
proc repeat(text: string, x: int): string =
result = ""
for i in 0 .. x:
result.add($i)
- 可能であればprocを使い、より強力な機能であるmacroやtemplate、iterator、converterは必要なときに使う。
- 自身のスコープ内で変わらない変数を宣言するときは、
let
文を使う(var
文ではなく)。let
文を使うことで変数がイミュータブルであることを保証し、そのコードの目的を読む人にわかりやすくする。
複数行の分や式の規則
- 一行より長いタプルは一行上のパラメーターと並ぶようにインデントされるべきである。
type
LongTupleA = tuple[wordyTupleMemberOne: int, wordyTupleMemberTwo: string,
wordyTupleMemberThree: float]
- 同様に、一行より長い関数や関数型の宣言でも同じことをする。
type
EventCallback = proc (timeReceived: Time, errorCode: int, event: Event,
output: var string)
proc lotsOfArguments(argOne: string, argTwo: int, argThree: float
argFour: proc(), argFive: bool): int
{.heyLookALongPragma.} =
- 複数行の関数呼び出しは開いたままの括弧を同じ縦列で連ねるべきである(複数行の関数宣言と同様)
startProcess(nimExecutable, currentDirectory, compilerArguments
environment, processOptions)