プログラミングのコード記法のひとつにヨーダ記法と言う物があります。定数を前に持ってくることで、代入になるような記述ミスやヌルポ発生を防ぐという物です。
C
1if (42 == val) { 2 // ... 3}
もし、42 = val
と記述ミスをしても、コンパイルエラーになるため、そのミスを防ぐことができます。
Java
1if ("42".equals(str)) { 2 // ... 3}
もし、str
がnullであったとしても、NullPointerExceptionが発生せずに、falseとなるだけです。
しかし、この記法は「SVO」ではなく「OVS」になるため、一般的な言語として考えたときのコードとしては違和感が強く、わかりにくいとされています。
さて、このヨーダ記法について、わかりにくいとか、生理的に受け付けないとか、嫌いだとか、主観的な意見を__求めてはいません__。私が求めるのは本当にこの記法が必要なのかという事です。
ほとんどのコンパイラでは、適切なオプションが付いていれば、if (val = 42) {...}
のような記述に対して警告を発します。また、優れたエディタで適切なlinterを使用していれば、コンパイルすることも無く、おかしな書き方をしていることを警告してくれるでしょう。言語によっては、代入が値を返さない、if文の条件式は真偽値しか受けてつけない、などの動きとすることで防止する物もあります。
しかし、JavaのNullPointerEcextion防止については、そのような防止をしてくれるわけではありません。かといって、毎回次のように書くことも冗長だと思われます。
Java
1if (str != null && str.equals("42")) { 2 // ... 3}
そもそもnull安全では無いJavaを使うのが悪いというもっともな意見もあるかと思いますが、このように言語や使いどころによってはヨーダ記法は未だに有用では無いのでは無いかと思っています。
上記のJavaのNullPointerEcextion防止のように、適当な回避策が無いため、ヨーダ記法が有用になる場面は他にあるのでしょうか?それとも、Javaの書き方も実は他に良い回避策があって、ヨーダ記法が有用になる場面など既に存在しないと言えたりするのでしょうか?ヨーダ記法を使うべきか、使うのであれば、どの言語のどのようなときなのかを教えていただきたいと思います。
この質問は、c - ヨーダスタイルについて - スタック・オーバーフローを見かけて、回答を書こうとしたときの疑問からです。該当の質問は主観的とされて閉じられていますが、ヨーダ記法の是非は問うべきとして、今回の質問をしました。なお、私自身の回答は「代入演算子に=
を使うのが悪い」という斜め下の結論になったため、投稿はしていません。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答18件
0
ベストアンサー
本質の回答にはなりませんが、Java7からObjects.equalsというメソッドが登場したので、nullチェックせず同値判定できるようになりました。
投稿2017/02/01 13:34
総合スコア20669
0
こんにちは。
ツールのできが悪い時やツールに頼らないケースでは有用と思います。
Visual Studioは警告レベル4でないと警告してくれませんが、4にすると未使用パラメータなども警告してきてたいへんウザいです。そして、デフォルトは3のようです。このようなケースでは警告レベルを4にするよりヨーダ記法を使う人もいるのではないかと思います。
C++はifの条件式で変数宣言を書けます。ここに書くことでその変数のスコープをif文内に限定できます。
条件判定に使った結果をthen節やelse節でも使いたい場合もそこそこあるので便利です。(実はclangのソースを読んでいる時に初めてこの使い方を見て衝撃でした。)
それとひと目で判別したい場合にもヨーダ記法は有用だろうと思います。
といいつつ、私自身はどうも馴染めないのでヨーダ記法は使わないですけどね。
私自身の回答は「代入演算子に=を使うのが悪い」
なるほど。PASCALなら:=
だから良いですね。
C言語が:=を選択していれば不幸になるプログラマがそこそこ減ったでしょう。
投稿2017/02/01 14:35
編集2017/02/01 14:43総合スコア23272
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/02 03:07
0
既に解決済みではありますが、結構深く考察されている記事を見つけたので、後から参照する方の為にリンクしておきます。
エラー防止のためだけに敢えて採用する必要も無いけれど、コーディングスタイルについて考察する上では面白いテーマかもしれません。
ヨーダ記法とは 〜定数を左辺に記述するメリットと流行らない理由〜
ヨーダ記法のススメ ─ 比較対象を左辺に記述するメリット
いずれも同じ方の書かれた記事です。
投稿2017/02/07 04:18
総合スコア5936
0
直接質問への回答となるものではありませんが、Basic系の言語では、代入は文であるとして、式中の代入自体を不可能とすることで、両者を=
で表現してある例がありました。
※ Basicのシンタックスハイライトがないようです ' 上の文は下の文の短縮形 a = 1 Let a = 1 ' 代入以外の文脈では、= 1つで比較として扱われる If a = b Then ' 略 End
VB.NETではどうなっているのかと思ったら、やはり代入も比較も=
のままでした。ということで、a = b = c
は、他言語のような「a
とb
にc
を代入する」のではなく、「b = c
の比較結果をa
に代入する」となります。
投稿2017/02/01 14:25
総合スコア145930
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/01 14:35
2017/02/01 22:15
0
a == 0
の形には、単にそういう慣習が多いという以上の積極的な理由はないと思います。
当初、この定数を後に書く形が好まれたのは、演算命令の後にオペランドが置かれるという、機械語やニーモニックからの類推によるのでしょう。仮にコンピュータというものが最初からスタックマシンとして構想されていたら、定数を先に書くほうが一般的になっていたかもしれませんよね。
私は、言語の構文規則で許されていることであれば、基本的にやっていいと思っています。ここまで前置き。
定数との比較では、比較される定数の値が重要なことが多いので、定数を前にすることはよくやります。後ろに回すと比較対象の違いが見つけにくいです。
大小関係や範囲の比較のとき、32 < c && c < 128
や128 <= c
のようなのは頻繁に使います。不等号の向きがそろうようにしておけば、条件を追加・除外・反転させるときも、間違いが起きにくいです。
投稿2017/02/02 03:25
編集2017/02/02 03:33総合スコア4443
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/02 03:26
2017/02/02 11:50
2017/02/02 12:19
2017/02/02 13:18 編集
2017/02/02 13:22
2017/02/02 15:30
2017/02/02 21:29
0
あの忌々しい書き方はヨーダ記法というのですね。初めて知りました。
あれが有用な場面など想像がつきませんが、イコールならまだ良いです。たまに不等号でも定数を左にしているのを見かけますが、混乱するのでやめていただきたいと思います。経験の浅い人がヨーダ記法を見て定数は左に書くものだと誤解したのでしょうか……。
投稿2017/02/01 14:54
総合スコア5944
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/01 15:16
2017/02/01 15:30
2017/02/01 15:54
2017/02/01 16:21
2017/02/01 18:56 編集
2017/02/01 22:33
0
古くからヨーダ記法を慣習として定着させているプロジェクトであり、かつそれが大規模であれば、ヨーダ記法が効力を発揮すると思います。大きなプロジェクトは様々な関係者が習慣や慣れを最適化の指針にしているケースが多く、その慣れを撤廃するのが工程ロスを誘発しかねないからです。
言い換えると、記法の差というより習慣の差として顕現しやすい話であり、バグ総数や可読性に対してヨーダ記法は定量的な改善効果をもたらす話では無いと私は考えています。
投稿2017/02/01 14:10
総合スコア14
0
代入に = を使うのが悪いというのは私もプログラミングを始めた頃に思いました。
A = A + 1 というイコールでないものをイコールで繋ぐ表現を大変気持ち悪く思ったことです。
日常的に馴染みのある = の使い方とプログラミングでの使い方の乖離がそもそもバグの原因となっていそうです。
本題ですが、自分の使っているツールがいつも使えるとは限らないので、ツールに関わらず間違いを少しでも減らす可能性があるなら使って悪い理由はないと思います。
また同様に使わない人を責める理由もないと思います。
特定の言語の使用時に於いてヨーダ記法を使うべき、使うべきでない、存在すべき、存在すべきでない、という議論は無意味に感じます。どちらにも決定的な材料はありません。
ただ、バグを減らす一助となるならその議論が警鐘を鳴らす役割はあるのかも知れません。
投稿2017/02/01 13:44
編集2017/02/01 13:50総合スコア28662
0
1 == a は a == 1 より読みにくい というのは
私にはよくわかりません。対称な式なのに。
英語の
a equals to 1 は 1 equals to a と同じ意味でやはり対称。
どちらも SVCで CVS と順が転倒するわけでは有りません。
比較対象の左が変数でないと読みにくくなるというのはぴんとこないです。
1 < a && a < 10 は普通ですよね。
有用性ですが、今まで何度も助けられたので、有用だと思います。
ツールで判定できるのは環境次第ですし代入を意図的に行うことも有ります。
コンパイルエラーで弾けるのは有用だと思います。
投稿2017/02/07 12:22
総合スコア62
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/07 12:47
2017/02/07 14:14
2017/02/07 22:35
0
正解がなさそうで難しい議題ですね。
最近の言語だったり、
古い言語でもメジャーバージョンアップで改良されつつあります。
もうすでにswordoneさんが回答されていますが、
Java7より同値判定できるメソッドが用意されました。
Java7以前では回避する方法として、
ヨーダ記法(という名前は初めてしりました)は回避策の一つとして、
有用でした。
ご存知だと思いますが、
HaskellやRustなどの関数型言語の大半は、
デフォルトでイミュータブルになっていると同時に、
仕様により、一昨日来やがれと言われるのでヨーダ記法ができません。
Rust
1fn main() { 2 const X: i32 = 1; 3 4 if X = 1 { 5 println!("X: {}", X); 6 } 7}
Elixirは代入+マッチという仕様になっていたりしますが、
コンパイルエラーとなります。
Elixir
1defmodule Yoda do 2 @teisu 1 3 4 if @teisu = 1 do 5 IO.inspect @teisu 6 end 7end
<<<使えないのです>>>
私も人のこと言えませんが、
現在所属している現場の人間は「プログラミングできます!(できるとは言ってない)」
みたいな人しかおらず、
こんな私が一番知識ある人間となっています。
以前のソースを見たりすると、
ヨーダ記法もへったくれもありません。
ごっちゃごちゃです。
そういう人の為には、
ヨーダ記法とか使わない(感じさせない)ほうが良いです。
1人または、スペシャリストと開発する分にはよいかもしれませんが、
その場合はもっと良い書き方ができるでしょう。
と私個人は思います。
投稿2017/02/03 03:37
総合スコア882
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/03 11:58
2017/02/03 14:53
2017/02/03 15:26
0
結論を言えばケースバイケースと私は考えています。これは、コーディングの際に何を優先するのかによると言い換えていただいて問題ありません。
私はコーディングの際、特に以下のことを気をつけています。
- 読みやすいこと
- 改修が容易であること
- ミスをし辛い書き方であること
- 高速に動作すること
「読みやすいこと」とは、コーディングがコメント文の代わりになるような、センテンスなものであることを指しています。raccyさんが記載されている通り、ヨーダ記法は慣れていないと文章に起こしにくく、この部分を優先する必要がある、特にロジック周りの箇所でこの記載は受け入れられづらいものです。
「改修が容易であること」とは、読みやすさと混同されがちですが、”同様の記法を1つの機能セットで統一できる”ことを指しています。ヨーダ記法では関係が薄いので省略しますが、ユーティリティをプロジェクトで統一する / しない理由になったりします。
「ミスをし辛い書き方であること」とは、raccyさんが記載されている通りのことです。NullPointerExceptionなどを避けたい場合に有用ですね。ただし、他の方も軽く記載していますがNull値のまま処理が進んでいくことはリスクのある事です。Javaなどでは”Null”と文字列で出てしまいますから(笑)(いや、これが結構よくあって笑い事では済まないんですけどね・・・)
私の場合はNull値に四則演算が発生しない場合にヨーダ記法を用いることがあります。
「高速に動作すること」とはそのままの意味ですが、これがヨーダ記法が用いられる最大の理由ではないかと私は考えています。
私がシステム全体から呼び出されるユーティリティメソッドなどを作る際にはほぼこの記法で記載しています。呼び出される回数が尋常では無いメソッドでは、1つの条件文が大きなパフォーマンス低下を呼びます。今のCPUは良くわからないのですが、昔Z80というCPUの命令セットでは判定に7、条件分岐に10クロックを必要としました。おそらく今もそう変わらないはずですし、パフォーマンス結果にも現れています。
色々書きましたが、人間側から離れるほどヨーダ記法はより優れた記法になると私は考えています。前置記法、中置記法、後置記法などと同じでしょう。
高機能なコンパイラはこれらの優劣を大分緩和してくれるようになりました。人間が努力するのではなく、コンパイラ側で対応するのがより良いという思想ですね。これは一般的なプログラマーはヨーダ記法を避けるべきとも思えますが、結局根本の部分ではこの記法、または別の「一般的」に使われない記法で高速化している機構があるはずで、つまりはこの記法は要らなくならないということです。
大分見かける機会が増えましたが、ワークフローをマウス操作で作れるようになっているサービスがあります。(「テーブルのカラム名」「次の文字列に一致」「テスト」のようなものです)
これがより一般的となれば、コーディング部分を書くことが「古い記法」となる未来があるかも知れません。でもそのときでも裏側はコーディングで支えられていて、記法自体が不要とはならないだろうと思います。
見返してみると冗長ですね。質問の回答になっていれば幸いです。
投稿2017/02/02 14:21
総合スコア12
0
わかりきった回答かもしませんが、プログラミングをはじめて間もない人にとっては有用ではないでしょうか。
サンプルコードなどを見よう見真似で書いている内はタイピングミスも多く、バグが起こったらそれがどこで発生しているのかがわからないものだと思いますので、そうした混乱を多少は防げると思います。
また、記事を書く側も対象者がそうであれば、サンプルコードを記述する際、あえてそのようにしても良いかとも思います。(といっても自分もあまりしませんが・・・)
それなりに意義を持って生み出された手法ですから、今をもっても必要とされると考えます。
一方、古き時代の産物にすがらず、今ある望ましい形に慣れることも必要だとは思います。
投稿2017/02/02 03:21
総合スコア146
0
個別言語のタグが付いてないので、言語に依らない話だとすると、「わかりやすさを犠牲にして、トリッキーに書けば短く書けるよ」ということの一例だと思うので、それを有用と思うかどうかと言う価値観の問題ではないでしょうか?
例に挙げておられるJavaの例についても、strがnullの時に例外でなくif条件を偽にしたいのであればif (str != null && str.equals("42"))
と書けば良いだけの話で、短く書く事を有用と思うかどうかはやはり価値観(主観)の問題でしかないと思います。
投稿2017/02/01 14:20
総合スコア85766
0
代入記号は数学における等号の意味ではありません。ここまでは共通事項だと思います。ですが、以下の記述には賛成できません。
この記法は「SVO」ではなく「OVS」になるため、一般的な言語として考えたときのコードとしては違和感が強く、わかりにくいとされています。
数学のおける等号や、プログラミングにおける関係演算子「==」は対称性をもちます。また、「状態」を意味するものであるので、英文法で例えるならば「SVC」型の文型と考えることが自然と思います。一方、「動作」を意味する代入演算の場合の方が「SVO」型であり、非対称性を持つことにも妥当性があると思います。
投稿2017/02/01 14:11
総合スコア4830
0
JavaScriptも仲間に入れていいんでしょうか。
phpや他の代入後の値をbooleanとして型変換できるスクリプト言語はありますが、
開発ルールとしてわかりやすさを優先することはできます。
ですがサーバで読み出しブラウザで実行するJavaScript(Node.jsやNashornを除くような)は
通信量を削減するために余計な文を削るインセンティブがあり、
わかりやすさを犠牲にする理由が残ります。
JSで検査内容が検査先より左に来る例外を一つあげると、RegExpがあると思います。
if (/^[0-9A-F]+$/.test(username))...
のようなケースで、
usernameがnullやundefinedになり得るなら、
if (username!=null&&username.match(/^[0-9A-F]+$/))...
としないといけませんが、長くなります。
if ((username+"").match(/^[0-9A-F]+$/))...
としてもまだ最初より長いです。
また定数ではないですが、if(a=func())...
のようなコードが、
代入と評価を同時に行うことを目的として
a=func();if(a)...
のかわりとして使用されることがあるので
これを if(func()==a)
として書くことで
代入を意図していないことがはっきりするでしょう。
JSはJavaやCのように実行前にコンパイルをするのではなく、
異なる開発元が提供するクライアントの実行環境に、
副作用のある他のライブラリとともにロードされてから初めて
必要な機能が揃っているかどうかがわかります。
汎用的なライブラリを作成する時などは Object.is() があることを仮定できず
Javaよりも深刻なのではないでしょうか。
Cの場合はマクロを組んでしまえば長いコードを短縮することもできます。
投稿2017/12/20 03:30
総合スコア97
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/12/20 12:02
2017/12/20 12:41
0
Javaに限ると。
strにnullがありえるなら短いコードで書け、テストの際の全網羅分岐確認も少なくて済む。
(null時にエラーとしない前提)
私は好きなので使ってますが、使ってた人は1人しか知らないので、多数決で不要。
投稿2017/02/02 00:34
総合スコア213
0
この書き方、名前があったんですね。
始めてみた時、混乱して全然理解出来なかったのを覚えています。
回答から全く離れていきますが、「代入演算子に=を使うのが悪い」に非常に共感を覚えたので、どうしてもコメント残したくて書き込んでしまいました^^;
いろいろスッキリしました。
投稿2017/02/01 14:16
退会済みユーザー
総合スコア0
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/01 13:41
2017/02/05 07:49
2017/02/05 08:19
2017/03/03 07:35 編集