たとえば、このワンライナーを使用しますか
int median(int a, int b, int c) {
return (a<b) ? (b<c) ? b : (a<c) ? c : a : (a<c) ? a : (b<c) ? c : b;
}
または、複数のreturnステートメントを含むif/elseソリューションですか?
時である ?:
適切であり、そうでないのはいつですか?初心者に教えたり、隠したりすべきですか?
三項演算子は悪ですか?
いいえ、それは祝福です。
いつですか?:適切ですか?
それが非常に単純なものである場合、多くの行を無駄にしたくないでしょう。
そしてそれはいつですか?
たとえば、例のように多くの連鎖演算子を使用すると、コードの可読性と明確性が損なわれ、注意が不十分なためにミスが発生する可能性が高くなります。
リトマステストは、コードが長い目で見れば簡単に読みやすく、保守が容易であることに疑問を抱き始めたときです。その後、それをしないでください。
ネストされていない三項演算子(つまり、1度しか使用されないステートメント)は問題ないと思いますが、複数のネストをしていると、読みにくくなります。
いつですか:適切
そしてそれはいつですか?
3項式の内部にロジックまたは関数の呼び出しがある場合は、見づらくなります。
誰も指摘していない(私が思う)1つの違いは、if-elseは値を返すことができないのに対し、3項演算子は返すことができるということです。
F#から来て、パターンマッチングを模倣するために三項演算子を使用したい場合があります。
match val with
| A -> 1
| B -> 3
| _ -> 0
対
return val == A ? 1 :
val == B ? 3 :
0;
有効な使用例(IMHO):
printf("Success in %d %s\n", nr_of_tries, (nr_of_tries == 1 ? "try" : "tries"));
これにより、2つの異なる印刷ステートメントよりもコードが読みやすくなります。ネストされた例は次のように依存します:(理解できる?はい:いいえ)
絶対に悪ではありません。実際、それは pure であり、if-then-elseはそうではありません。
Haskell、F#、MLなどの関数型言語では、悪と見なされるのはif-then-elseステートメントです。
これは、命令的なif-then-elseステートメントのような「アクション」では、変数宣言をその定義から分離する必要があり、関数に state が導入されるためです。
たとえば、次のコードでは:
const var x = n % 3 == 1
? Parity.Even
: Parity.Odd;
vs.
Parity x;
if (n % 3 == 1)
x = Parity.Even;
else
x = Parity.Odd;
最初のものは、短くなること以外に2つの利点があります。
x
は定数であるため、バグが発生する可能性がはるかに少なく、2番目の方法では実現できない方法で最適化できる可能性があります。x
がParity
である必要があると簡単に推測できます。紛らわしいことに、関数型言語では、三項演算子はしばしばif-then-elseと呼ばれます。 Haskellでは、x = if n mod 3 == 1 then Odd else Even
。
その特定の表現は私の目を傷つけます。それを維持できないので、それを使用した私のチームの開発者は誰でも暴力を振るうでしょう。
三項演算子は、上手に使えば悪ではありません。それらは単一行である必要さえありません。適切にフォーマットされた長いものは、非常に明確で理解しやすい場合があります。
return
( 'a' == $s ) ? 1
: ( 'b' == $s ) ? 2
: ( 'c' == $s ) ? 3
: 4;
私は同等のif/then/elseチェーンよりもそれが好きです:
if ( 'a' == $s ) {
$retval = 1;
}
elsif ( 'b' == $s ) {
$retval = 2;
}
elsif ( 'c' == $s ) {
$retval = 3;
}
else {
$retval = 4;
}
return $retval;
それらを次のように再フォーマットします。
if ( 'a' == $s ) { $retval = 1; }
elsif ( 'b' == $s ) { $retval = 2; }
elsif ( 'c' == $s ) { $retval = 3; }
else { $retval = 4; }
return $retval;
条件と割り当てが簡単に調整できるかどうか。それでも私は三項バージョンを好んでいます。なぜならそれはより短く、条件と割り当ての周りにそれほど多くのノイズがないからです。
ReSharper VS.NETでは、if...else
とともに ?:
演算子。
ReSharperは、条件/ブロックが特定の複雑さのレベルを下回る場合にのみ提案するようです。それ以外の場合は、if...else
。
is evilの例を次に示します。
oldValue = newValue >= 0 ? newValue : oldValue;
混乱して無駄です。コンパイラーは2番目の式(oldValue = oldValue)を最適化しますが、なぜコーダーが最初にこれを行ったのですか?
別の愚か:
thingie = otherThingie != null ? otherThingie : null;
一部の人々は単にコーダーであることを意図されていません...
Gregは、同等のifステートメントは「うるさい」と言っています。うるさく書いてしまった場合です。しかし、次のように書くことができる場合も同じです。
if ('a' == $s) return 1;
if ('b' == $s) return 2;
if ('c' == $s) return 3;
return 4;
これは、3値よりもノイズが多くありません。ターナリーショートカットかしら。すべての式が評価されますか?
3項演算子は悪であるどころか、天の恵みです。
入れ子式で決定を行う場合に最も役立ちます。古典的な例は関数呼び出しです:
printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
特定の例では、3項はreturn
の下の最上位の式であるため、ほとんど必要ありません。 return
キーワード以外を複製せずに、条件をステートメントレベルに上げることができます。
N.B.中央値の特定のアルゴリズムを読みやすくするものはありません。
「悪」な議論はさておき、私の経験では、プログラマーの三項演算子の使用と、彼または彼女のコードベース全体の読み取り、追跡、維持が困難である可能性(完全に文書化されていない場合ではない)との間に高い相関があることを発見しました。プログラマーが自分のコードを理解できるよりも、1〜2文字の行を節約することに関心がある場合、3進ステートメントを理解するための小さな混乱は、通常、氷山の一角です。
三項演算子は、s ** tがハエを引き寄せるように、マジックナンバーを引き付けます。
特定の問題を解決するためのオープンソースライブラリを探していて、そのライブラリの候補に元の投稿者の三項演算子などのコードがあった場合、警告ベルが頭から消え始め、先に進むことを検討し始めました。借りる他のプロジェクトに。
悪の?ほら、違うだけです。
if
はステートメントです。 (test ? a : b)
は式です。彼らは同じものではありません。
値を表現するための式が存在します。アクションを実行するためのステートメントが存在します。式はステートメント内に表示できますが、その逆はできません。そのため、合計の項やメソッドへの引数など、他の式内で三項式を使用できます。 する必要があるではありませんが、-したい場合はできるです。何も問題はありません。それを悪だと言う人もいるかもしれませんが、それは彼らの意見です。
三項式の1つの値は、trueとfalseの両方のケースを処理できるようにすることです。 if
ステートメントにはありません。
読みやすさが気になる場合は、読みやすくフォーマットできます。
どういうわけか「悪」はプログラミング語彙に忍び込んだ。誰が最初にそれを落としたのか知りたいです。 (実際には、私は容疑者がいます-彼はMITにいます。)私はむしろ、人々の好みや名前を呼ぶだけでなく、この分野での価値判断に客観的な理由があった方がいいです。
これは、if/elseの組み合わせと同じように見栄えがするように再フォーマットできます。
int median(int a, int b, int c)
{
return
(a<b)
?
(b<c)
? b
:
(a<c)
? c
: a
:
(a<c)
? a
:
(b<c)
? c
: b;
}
しかし、問題は、実際に何が起こるかを表すインデントの権利を取得したかどうか本当にわからないことです。 :-)
言ってもいいですか? 3項演算のこの特定のアプリケーションを見つけることができませんevil:
どうかどうかご容赦ください、私の評判はすでにかなり哀れです。
コードを醜くするものは何でも悪です。
コードをよりクリーンにするために三項を使用する場合は、必ずそれを使用してください。時々phpのようにインライン置換をするのは素晴らしいことです。
"Hello ".($Male?"Mr":"Ms")." $Name
これは数行を節約し、それはかなり明確ですが、あなたの例は明確にするために少なくともより良いフォーマットが必要であり、三項は複数行には本当に良くないので、if/elseを使うこともできます。
最大の勝利:アクションのターゲットが1つあることを示します。
if ( $is_whatever )
$foo = 'A';
else
$foo = 'B';
たどることができる2つのコードパスがあり、リーダーはどの2つの変数が設定されているかを注意深く読む必要があります。この場合、変数は1つだけですが、読者はそれを理解するためにさらに読む必要があります。結局のところ、それはこれである可能性があります:
if ( $is_whatever )
$foo = 'A';
else
$bar = 'B';
三項演算子を使用すると、設定されている変数が1つだけであることは明らかです。
$foo = $is_whatever ? 'A' : 'B';
最下位レベルでは、DRY(Do n't Repeat Yourself))原則が最も基本的です。$foo
を1回だけ指定できる場合は、そうしてください。
場所があります。私は、開発者のスキルレベルがひどいものからウィザードまでさまざまな会社で働いています。コードを維持する必要があり、私は永遠にそこにいるわけではないので、コードがそこに属しているように書こうとします(私のイニシャルでコメントを見ないで、あなたができることは非常にまれです私が取り組んだコードを見て、どこに変更を加えたかを確認します)、そして自分よりもスキルの低い人でもそれを維持できることを確認します。
三項演算子は見た目が素晴らしく、格好良いように見えますが、私の経験では、コード行を維持するのはほぼ不可能です。私の現在の雇用主には、20年近く出荷されている製品があります。私はその例をどこにも使用しません。
三項演算子が悪いとは思わない。
ここに私を困らせた落とし穴があります。私は多くのCプログラマー(10歳以上)で、1990年代後半にWebベースのアプリケーションプログラミングに移りました。私はすぐにWebプログラマーとして、PHPにも三項演算子が含まれていることに遭遇しました。PHPプログラムにバグがあり、最終的に行にたどり着きましたネストされた3項演算子を使用したコードの例PHP 3項演算子は左から右に関連付けられていますが、Cの3項演算子(以前使用していた)は右から左に関連付けられています。
いつ適切で、いつ適切でないのですか?
同種の人々のために開発する場合は問題ないと思いますが、異なるレベルを扱う人々を扱う必要がある場合、この種のワンライナーはコードにさらに複雑なレベルを導入するだけです。したがって、この問題に関する私のポリシーは、コードを短くして123123回説明するのではなく、コードを明確にして説明しないことです。
初心者に教えたり、隠したりすべきですか?
私は初心者に教えられるべきではありません。むしろ、必要が生じたときにそれを理解することを彼らに好むので、必要なときにだけ使用され、ifが必要になるたびに使用されるわけではありません。
定期的に 600-1200行のメソッドを記述しているショップすべきではない三元語は「理解しにくい」と教えてくれます。 定期的にが5つの条件でコード分岐を評価できる任意のショップすべきではない 3項で具体的に要約された条件は「読みにくい」と私に教えてくれます。
IMO、演算子自体は悪ではありませんが、C(およびC++)で使用される構文は非常に簡潔です。 IMO、ALGOL 60の方が優れていたので、次のようにします。
A = x == y ? B : C;
これはよりこのようになります(ただし、一般にCのような構文に固執します)。
A = if (x==y) B else C;
それでも、ネストが深すぎると可読性に問題が生じる可能性がありますが、少なくともA)プログラミングを行った人なら誰でも簡単なものを理解でき、B)理解している人ならかなり簡単にかなり深いネストを処理できます。 OTOH、私はまた、LISP(たとえば)でcond
は3項ステートメントに非常に似ていることに注意してください。ステートメントのセットではなく、単一の式が値を生成します(そして、ほとんどの場合、 LISPはそのようなものです...)
?が適切な場合と適切でない場合
初心者に教えるか、それとも非表示にする必要がありますか?
関係ありませんが、「初心者」が学習するには複雑すぎないため、意図的に非表示にしないでください。
もし...それから...他の場合は条件を強調する傾向があり、したがって条件付きで実行されている操作の強調を解除します。
三項演算子はその逆で、条件を隠す傾向があり、実行される操作が条件自体よりも重要な場合に便利です。
いくつかの言語では、マイナーな技術的な微妙な問題があります。1つはステートメントであり、もう1つは式であるため、それらはまったく互換性がありません。 C++でのconstの条件付き初期化