ヨーダ記法

ヨーダ記法（ヨーダきほう、Yoda notation）またはヨーダ条件式（ヨーダじょうけんしき、Yoda conditions）とは、プログラミングにおけるジャーゴンのひとつで、If文などの条件式において比較するふたつの要素を一般的な順序と逆に記述するプログラミングスタイルをいう。ヨーダ記法では条件式の左辺（比較演算子の左オペランド）に定数を配置する。 映画『スター・ウォーズ』シリーズの登場人物・ヨーダが、標準的ではない英語の文法で話すことに由来する。 ヨーダ記法はWordPressやSymfonyのPHPコーディング標準の一部に採用されている。一方、CakePHPのコーディング規約では、ヨーダ記法は避けるべきとされている。 例えばC言語やC++において、int型の変数valueの値を調べて分岐するif文は、多くの場合、以下のように記述される。 if ( value == 42 ) { /* ... */ } // 上記は「もし value が 42 と等しければ、…」と読める。 ヨーダ記法では同様の式を逆に記述する。 if ( 42 == value ) { /* ... */ } // 上記は「もし 42 が value と等しければ、…」と読める。 等値比較の演算子==の左オペランドと右オペランドは入れ替えても結果に変わりはないことを利用している。 定数42は比較演算子==の左側に書かれ、中身を調べようとしている変数valueは右側に書かれるという順序を、ヨーダの独特のしゃべり方（目的語-主語-動詞、OSV型）に見立てている。（例: “When nine hundred years old you reach, look as good you will not."） 式における定数の位置はプログラムの挙動を変更しない[要校閲]（ただし後述[どれ?]のようにfalseに評価される場合[要説明]や、ユーザー定義の演算子オーバーロードが存在する場合を除く）。 Cに代表されるような、代入演算子に等号ひとつ (=) を使い、等値比較の演算子には==などの別のトークンを使うプログラミング言語では、比較式のつもりで代入式を書いてしまう間違いが見られる。 例えばC/C++では下記コードは合法であり、コンパイルエラーにならない。代入演算子=は左辺に格納されたものと同じ値もしくは参照（左辺値）を返すからである。結果として、プログラムの実行段階になってようやく動作異常に気づき、記述ミスの発覚が遅れる可能性がある。 int myNumber = 0; /* ... */ if (myNumber = 42) { /* ... */ } // まず myNumber に 42 が代入され、代入後の myNumber が持つ値すなわち 42 が if 文の条件式として評価される。 // 結果として、myNumber の代入前の値が何であっても、if 文の条件式は非ゼロすなわち真となる。 上記をヨーダ記法で書き換えると、以下のようになる。 int myNumber = 0; /* ... */ if (42 = myNumber) { /* ... */ } // シンタックスエラーとなりコンパイルされない。 42は定数（リテラル）であり、変更されない（できない）ため、このエラーはコンパイラに捕捉される。結果として、コンパイル段階で記述ミスに気づくことができる。 C/C++とは異なり、JavaやC#の場合は、条件式の型はそれぞれbooleanやboolでなければならない仕様となっている。そのため、条件式を書くべきところに間違えて代入式を記述してしまっても、ほとんどのケースではコンパイルエラーになるが、例外もある。 例えば下記はJavaでも合法であり、コンパイルエラーにはならないが、本来プログラマーが意図していたコードはflag == trueである。 boolean flag = false; /* ... */ if (flag = true) { /* ... */ } // 条件式は常に真と判定されてしまう。 このようなミスを防ぐためには、flag != falseと書くか、あるいはヨーダ記法を使ってtrue == flagと書く方法もあるが、そもそもboolean型の変数をtrueやfalseと比較するのは冗長である。真を期待する場合は条件式にそのまま使用し、偽を期待する場合は論理否定演算子!で反転してから条件式に使用すればよい。 boolean flag = false; /* ... */ if (flag) { /* ... */ } 下記はJavaにおいて、プリミティブラッパークラスjava.lang.Booleanからプリミティブ型booleanへの暗黙的なボックス化解除（オートアンボクシング）が実行されることで異常動作を引き起こす例である。 Boolean myBoolean = true; /* ... */ if (myBoolean = null) { /* ... */ } // まず java.lang.Boolean 型の変数に null が代入された後、java.lang.Boolean.booleanValue() が暗黙的に呼ばれる。 // コンパイルは通るが、実行時に Java ランタイム環境によって例外 NullPointerException がスローされる。 ヨーダ記法では: Boolean myBoolean = true; /* ... */ if (null = myBoolean) { /* ... */ } // シンタックスエラーとなりコンパイルされない。 Java 8以降はjava.util.Objects.isNull(Object)を使う方法もある。 C#の場合はboolのような組み込みの値型もすべてSystem.ValueTypeから派生するオブジェクトであり、プリミティブラッパークラスのようなものは不要である。また、暗黙的なボックス化解除もされず、値を取り出すにはキャスト演算子を使って明示的に変換する必要があるため、上記のような問題は起きない。ただし、boolへの暗黙変換演算子をユーザー定義していたり、true/false演算子をユーザー定義していたりすると、上記のJavaにおける例のような間違ったコードを書くことができてしまう。とはいえ、2つの参照の等値性比較にはObject.ReferenceEquals(Object, Object)を使うことができるし、C# 7.0以降はis演算子を使ってif (obj is null) {...}と書くこともできるので、問題を避けるためにヨーダ記法を使う必要はない。 また、null値のデリファレンスによる危険な振る舞いを回避するのに使える場合もある。 String myString = null; /* ... */ if (myString.equals("foobar")) { /* ... */ } // myString が null だった場合、Java ランタイム環境によって例外 NullPointerException がスローされる。 ヨーダ記法では: String myString = null; /* ... */ if ("foobar".equals(myString)) { /* ... */ } // 文字列リテラルは常に non-null であり、NullPointerException は発生しないことが保証される。 // また、Object.equals(Object) メソッドの引数に null が渡された場合は false が返却される。 // そのため、myString が null だった場合、期待通りに false と判定される。 Java 7以降はjava.util.Objects.equals(Object, Object)を使う方法もある。ただし文字列の大文字・小文字を区別せずに比較する場合、インスタンスメソッドのString.equalsIgnoreCase(String)を使う必要がある。 C#の場合は文字列の比較にはインスタンスメソッドのObject.Equals(Object)ではなく、両辺にnullを許可する==演算子オーバーロードを使い、また前述のように条件式の型はboolでなければならないため、少なくとも文字列の比較に関してヨーダ記法を使う必要はない。大文字・小文字を区別せずに比較する場合、インスタンスメソッドだけでなくnullを許可する静的メソッドも用意されている。 string myString = null; /* ... */ if (myString == "foobar") { /* ... */ } // myString が null だった場合、false と判定される。 if (myString = "foobar") { /* ... */ } // シンタックスエラーとなりコンパイルされない。 正確にはヨーダ記法固有の利点ではないが、比較演算子を左側に寄せることにより人によっては可読性が増すという長所もある。特にこの長所は略語を使わない文化や型無しのオブジェクト指向言語で顕著となる。(型が無い場合は名前の重複を避けるためメソッドにつける名前が長くなりやすい)[独自研究?] "字句解析中に'/*'があるか判定する処理の一部" 2 = contextOfParser tokenStack size ifFalse: [