Igor Pro コーディング規約

Thomas Braun氏によってIgor Exchangeに投稿されているIgor Proのコーディング規約(非公式)が,簡潔で分かりやすかったので本人の許可を得て翻訳しました. ドキュメント作成ソフトのDoxygen等,日本のIgor Proユーザーにはおそらく馴染みのないものもありますが,規約の多くの部分がコーディングの参考にできると思います.

原文:

http://www.igorexchange.com/project/CodingConventions

https://github.com/t-b/igor-pro-coding-conventions

1 プロシージャ

  • コードはIgor Proの外部のプロシージャファイルに直接,書き込むべきです.

  • プロシージャファイル名はアルファベットの大文字小文字,アンダースコア,ハイフンのみで構成され,.ipfで終わります.

  • ファイルのエンコーディングはOSに依存します.しかし使用する文字は常にASCII文字に限られるべきです.Igor Pro 7でだけ使用するコードでは,テキストエンコーディングとしてUTF-8を用い#pragma TextEncoding = "UTF-8"を指定します.

  • プロシージャファイルは#pragma rtGlobals=3およびその説明コメント*1で開始されます.

  • 改行コードは常にUNIXスタイル(LF)を用いるべきです.

2 空白文字とコメント

コメント

  • ファイル,関数,マクロ,定数の説明(ドキュメント)にはdoxygenを用います.

  • 次のように,末尾のコメントの前には常に一つの空白文字を置くべきです.

if (a < 0)
  b = 1
else // positive numbers (including zero)
  b = 4711
endif
  • コメントを行末に付すよりは,行を分けて書くべきです.

Doxygen

  • doxygenのコメントは///で開始します.また,定義文の末尾で説明を加えるには///<を使うべきです*2

  • @paramキーワードに続けて引数の名前と説明を書く場合,引数の説明は関数に渡す順番に通りに並べるべきです.

/// @param pressure Pressure of the cell
/// @param temperature Outdoor temperature
/// @param length Length of a soccer field
Function PerformCalculation(pressure, temperature, length)
    variable pressure, temperature, length // code
End
  • 関数が引数の値渡しと参照渡し*3の両方を使うとき場合は,in/out指定を@paramに付けるべきです.
/// @param[in] name Name of the device
/// @param[out] type Device type
/// @param[out] number Device number
Function ParseString(name, type, number)
    string name
    variable &type, &number
// code
End
  • オプション変数の説明は次のようにします.
/// @param verbose [optional, default = 0] Verbosely output
///                                        the steps of the performed calculations
Function DoCalculation([verbose])
    variable verbose // code
End

空白文字

  • 各関数は他のコードから改行1行分だけ隔てて書くべきです.

  • インデントにはタブ文字を用い,(Igor Pro以外のソフトウェアでコーディングしていてタブ文字が使えない場合は)タブ文字には4つの空白文字を当てるべきです.

  • 行を分けてコメントする場合,コメントのインデントの深さは周囲のコードに合わせます.

  • 関数の引数の宣言,ローカル変数の宣言,関数の残りの部分はそれぞれ改行で隔てて書きます.

Function CalculatePressure(weight, size)
    variable weight, size

    variable i, numEntries

    // code
End
  • 数学演算子,2進数演算子,比較演算子および代入記号の前後にはひとつの空白を書きます.また,コンマ,セミコロンの後にも空白ひとつを書きます.
a = b + c * (d + 1) / 5

if(a < b)
    c = a^2 + b^2
end

Make/O/N={1, 2} data
for(i = 0; i < numWaves; i += 1)
    a = i^2
endfor

if(myStatus && myClock)
    e=f
endif
  • 行の末尾の余分な空白を避けるように心掛けてください.以下,空白文字を␣で,タブ文字を⇥で表します.
良い例:
Function␣DoStuff()
⇥print␣"Hi"

⇥if(a␣<␣b)
⇥⇥c␣=␣a^2␣+␣b^2
⇥end

⇥Make/O/N={1,␣2}␣data
End

悪い例:
Function␣DoStuff()␣
⇥print␣"Hi"␣⇥
⇥
⇥if(a␣<␣b)␣␣␣␣
⇥⇥c␣=␣a^2␣+␣b^2⇥
⇥end␣
⇥
⇥Make/O/N={1,␣2}␣data␣
End
  • if/endiffor/endfordo/whileswitch/endswitchのようなコードブロックがプログラムのロジックを表している場合には,前後には改行を入れます.
for(i = 0; i < numEntries; i += 1)
    // code
endfor

if(a > b)
    c=d
elseif(a == b)
    c=e
else
    c=0
endif

switch(mode)
    case MODE1:
        a = "myString"
        break
    case MODE2:
        a = "someOtherString"
        break
    default:
        Abort "unknown mode"
        break
endswitch

以下のような場合は,直前の代入文がロジックの一部なのでifforの前に改行を入れません.

numEntries = ItemsInList(list)
for(i = 0; i < numEntries; i += 1)
    // code
endfor

NVAR num = root:fancyNumber
if(num < 5)
    // code
endif

複数のend文が続く場合には,改行を省略します.

for(i = 0; i < numEntries; i += 1)
    // code

    if(i < 5)
        // code
    endif
endfor
  • 操作関数のフラグの間には空白を入れません.また,フラグへの代入を行う場合の=の前後にも空白を入れません.
良い例:
Wave/Z/T/SDFR=dfr wv = myWave

Function/S DoStuff() // code

End
悪い例: 
Wave /Z /T /SDFR = dfr wv = myWave
  • 引数の参照渡しに使う&は変数名の直前に置きます.
良い例:
Function DoStuff(length, height, weight)
    variable &length, &height, &weight
    
    // code
End

悪い例:
Function DoStuff(length, height, weight)
    variable& length, & height,& weight
    
    // code
End

3 コード

3.1 基本

  • 1行は80文字を超えないようにします.

  • variable/string/wave/dfrefの名前にはcamelCaseを使い,構造体の名前にはCamelCaseを使います.

  • GUIをコントロールするためのプロシージャには,古いスタイルの関数より構造体を用いた関数を使うべきです.

  • i, j, k, lという名前の変数はループカウンターとしてだけ使うべきです.後者ほど内側のループで使われます.

  • 一時的に値を格納するウェーブとして,フリーウェーブを使うべきです.

  • できる限りSetDataFolderを使わずにコードを書くべきです.関数が呼ばれるときに特定のデータフォルダをカレントフォルダとしていることを期待するなら,適切なドキュメントを書いておくべきです.関数中でカレントフォルダを変更した場合は常に,関数の終了前にカレントフォルダをもとに戻します.

  • Igor Proのコードは大文字小文字の違いを問題にしませんが,可読性の向上のため,Igor Proのヘルプファイルに書かれている公式の名称に合わせて大文字小文字を書き分けるべきです.

Make/N=(10) data
AppendToGraph/W=$graph data
WAVE/Z wv
SVAR sv = abcd
STRUCT Rectangular rect
print ItemsInList(list)

ただし,以下のふたつの場合は例外です*4

variable storageCount
string name
  • 変数や関数を定義するときや,それらを使うときには,大文字小文字の使い方を変えてはいけません.

  • 関数の戻り値とする値を,一時的に格納するために変数を使うべきではありません.

良い例:
if(someCondition) // code
    return 0 else
    // code
    return 1
endif
// 関数の戻り値が状態であることを知らせたいのなら,
// 関数名をGetStatusForFooのようにするか.doxygenのコメントとして@returnを使うべきです.
// あるいは,関数名とdoxygenコメントの両方を使うべきです.

悪い例:
variable status

// code

if(someCondition) // code
    status = 0
else
    // code
    status = 1
endif

return status
  • コメントアウトされたコードを残しておくべきではありません.

  • その必要がないなら,数値変数や文字列変数を初期化するべきではありません.もし変数の初期化を行うなら,それぞれ別の行で行うべきです.

良い例:
variable i = 1
variable numEntries, maxLength
string list

悪い例:
variable i = 0, numEntries = ItemsInList(list), maxLength
string list = ""
  • 関数のオプション変数としてデフォルト値を使うなら,それをわざわざ書くべきではありません.
良い例:
StringFromList(0, list)

悪い例:
StringFromList(0, list, ";")
  • 括弧は省略できるのなら省略するべきです.
良い例:
variable a = b * (1 + 2)

if(a < b || a < c)
    // code
endif

悪い例:
variable a = (b * (1 + 2))

if((a < b) || (a < c))
    // code
endif
  • 優先度が等しい演算子を組み合わせるときには,括弧を使うべきです.
良い例:
if((A || B) && C)
    // code
endif

if(A == (B >= C))
    // code
endif

悪い例:
if(A || B && C) // same as above as these are left to right
    // code
endif

if(A == B >= C) // same as above as these are right to left
    // code
endif

正確な結合則を記憶しておくのは難しく,エラーを起こしやすくなるからです. DisplayHelpTopic "Operators"も参照してください.

3.2 定数

  • あるファイルの内部でだけ有効なstatic定数は,そのファイルの先頭で定義します.
  • グローバル定数の名前はアルファベット大文字とアンダースコアのみで構成します,グローバル定数の定義はただ一つのファイルに集約されるべきです.
  • マジックナンバー*5にはコメントで説明をつけるべきです.
    static Constant DEFAULT_WAVE_SIZE = 128 // equals 2^8 which is
                                            // the width of the DAC signal

3.3 マクロ

  • マクロはウィンドウ再構成マクロとしてだけ使うべきです.
  • ウィンドウ再構成マクロを自分の手で書き換えるのは避けるべきです.パネルをデフォルトの状態に戻したいのなら,関数中でDoWindow/Rを呼び出し,Igor Proにマクロを書き換えさせるべきです.

3.4 関数

  • 関数の長さは50行(あるいは画面の高さの半分)に収めるようにします.

  • 関数名にはCamelCaseを用います(ファイル名を表すためにSomeString_といった接頭語を付けることは認められます).

  • 関数がそのプロシージャファイルの内部でしか使われないのなら,それらの関数はstaticにします*6

  • 次のように,すべての変数を関数の初めの部分で定義します.

Function CalculatePressure(weight, size)
    variable weight, size
    
    variable i, numEntries

    // code
End

これは,Igor Proではブロックスコープが存在しないからです*7.すなわち

if(someCondition)
    variable a = 4711
end

print a

は正しいコードです.これはC/C++経験者を混乱させます.

4 リンク・文献

*1:訳注:新しいプロシージャウィンドウを作成したときに書いてある#pragma rtGlobals = 3 // Use modern global access method and strict wave access.を消すべきではないということ.

*2:訳注:Variable num ///< number of points のように,変数定義等の直後にその説明を置く場合

*3:訳注:例のように,変数名の頭に&を付けて引数を受け取ると,関数内での変数値の変更が関数の呼び出し元にも反映されるようになります.この機能を変数の参照渡しと呼びます.

*4:訳注:Igor ProヘルプファイルではVariable,Stringは大文字で始まります.この例外はおそらく,組み込み型が小文字で書かれるC/C++の慣習に合わせたものでしょう.

*5:訳注:プログラムに現れる,ぱっと見て意味の分からない数字のこと.

*6:訳注:関数定義をFunctionのかわりにstatic Functionで始めると,プロシージャファイルの外からその関数が使えなくなります.ただし,#pragma ModuleName=SomeStringによってモジュール化するとstaticな関数をファイルの外からも使うことができるようになります.

*7:訳注:if/endifブロックの内部で定義した変数はブロックの内部でだけ有効(ブロックスコープ)だと便利ですが,Igor Proではそうなっていない,ということ.