たとえば、このワンライナーを好むだろうか
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ソリューションですか?
?:
適切な場合と適切でない場合 初心者に教えたり隠したりするべきですか?
たとえば、このワンライナーを好むだろうか
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ソリューションですか?
?:
適切な場合と適切でない場合 初心者に教えたり隠したりするべきですか?
回答:
三項演算子は悪ですか?
いいえ、それは祝福です。
いつですか?:適切ですか?
とても単純なもので、多くの行を無駄にしたくない場合。
それはいつですか?
コードの読みやすさと明確さが損なわれ、注意が不十分なためにミスが発生する可能性が高くなった場合(たとえば、例のように多くのチェーン演算子を使用した場合)。
リトマステストは、長い目で見ればコードの読み取りと保守が容易であることを疑い始めるときです。それをしないでください。
myVar = someExpression ? false : true;
(someExpression ? var1 : var2)++
:-)
ネストされていない3項演算子(つまり、1回だけ使用されるステートメント)は問題ないと思いますが、2つ以上をネストしている場合、読みにくくなります。
いつですか?:適切
それはいつですか?
三項式内にロジックまたは関数呼び出しがある場合、それを見るのが恐ろしくなります。
(私が思うに)誰も指摘していない違いの1つは、if-elseが値を返せないのに対し、三項演算子は返せるということです。
F#から来て、三項演算子を使用してパターンマッチングを模倣することが好きな場合があります。
match val with
| A -> 1
| B -> 3
| _ -> 0
対
return val == A ? 1 :
val == B ? 3 :
0;
var res = function() {switch(input) {case 1: return "1"; case 2: return "2"; ...}}()
スイッチを式としてエミュレートすることです。
expression
とstatement
:)が、私はいつも、私は彼らにラウンド間違った方法を取得し、自分自身の馬鹿を作ってあげる心配です
const
後で変更できない変数を初期化するためにCおよびC ++で役立ちます。
有効な使用例(IMHO):
printf("Success in %d %s\n", nr_of_tries, (nr_of_tries == 1 ? "try" : "tries"));
これにより、2つの個別のprintステートメントを使用するよりもコードが読みやすくなります。入れ子になった例は次のとおりです:(わかりやすい?はい:いいえ)
絶対に悪ではありません。実際、それは純粋で、if-then-elseはそうではありません。
Haskell、F#、MLなどの関数型言語では、悪と見なされるのはif-then-elseステートメントです。
その理由は、命令型if-then-elseステートメントのような「アクション」では、変数宣言をその定義から分離する必要があり、関数に状態を導入するためです。
たとえば、次のコードでは:
const var x = n % 3 == 1
? Parity.Even
: Parity.Odd;
対
Parity x;
if (n % 3 == 1)
x = Parity.Even;
else
x = Parity.Odd;
最初のものには、短くなること以外に2つの利点があります。
x
は定数であるため、バグが発生する可能性ははるかに低く、2番目の方法では不可能な方法で最適化できます。x
がtypeである必要があると簡単に推測できます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;
条件と割り当てが簡単に調整できる場合。それでも、私はそれが短く、条件と割り当ての周りにそれほどノイズがないので、三元バージョンを好みます。
これは、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;
}
しかし、問題は、実際に何が起こるかを表すためのインデント権を取得したかどうか、私には本当にわからないことです。:-)
if-else
構造よりもはるかに優れていると思います。キーはフォーマットです。
悪であるとはほど遠く、三項演算子は天の恵みです。
ネストされた式で決定を行う場合に最も便利です。典型的な例は関数呼び出しです:
printf("I see %d evil construct%s in this program\n", n, n == 1 ? "" : "s");
あなたの特定の例では、三項はaの下のトップレベルの式であるため、ほとんど無償return
です。return
キーワード以外のものを複製することなく、条件をステートメントレベルに引き上げることができます。
注:中央値の特定のアルゴリズムを読みやすくするものはありません。
printf("I see %d evil construct%s in this program\n", n, "s" unless (n == 1) "s");
「悪」の議論は別として、私の経験では、プログラマーの三項演算子の使用と、コードベース全体の読み取り、追跡、および維持が困難である可能性(完全に文書化されていない場合を除く)の間に高い相関があることがわかりました。プログラマが自分のコードを理解できる人よりも数文字の1〜2文字の行を保存することに関心がある場合、3項ステートメントを理解する小さな混乱は通常氷山の一角です。
三項演算子は、s ** tがハエを引き付けるように、マジックナンバーを引き付けます。
特定の問題を解決するためにオープンソースライブラリを探していて、そのライブラリの候補に元のポスターの三項演算子などのコードを見た場合、警告ベルが頭の中で鳴り始め、先に進むことを検討し始めました借りる他のプロジェクトに
ここでは、それは場合の例だある悪:
oldValue = newValue >= 0 ? newValue : oldValue;
紛らわしくて無駄です。コンパイラーは2番目の式(oldValue = oldValue)を最適化できますが、なぜ最初にコーダーがこれを行ったのですか?
もう一つのすごい:
thingie = otherThingie != null ? otherThingie : null;
一部の人々は単にコーダーになることを意図していない...
グレッグは、同等のifステートメントは「うるさい」と言います。うるさく書いた場合です。ただし、次のように記述できる場合は同じです。
if ('a' == $s) return 1;
if ('b' == $s) return 2;
if ('c' == $s) return 3;
return 4;
これは3項よりもノイズが多いわけではありません。三項の近道かしら?すべての式が評価されますか?
if (x != 0) x = 0;
...
悪の?見て、彼らはただ違うだけです。
if
ステートメントです。(test ? a : b)
式です。それらは同じものではありません。
値を表現する式が存在します。アクションを実行するためのステートメントが存在します。式はステートメント内に表示できますが、その逆はできません。したがって、合計の項やメソッドの引数など、他の式内で3項式を使用できます。する必要はありませんが、望むならできます。それには何の問題もありません。一部の人々はそれが悪だと言うかもしれませんが、それは彼らの意見です。
三項式の値の1つは、trueとfalseの両方のケースを処理できるようにすることです。if
ステートメントはしません。
読みやすさを心配している場合は、読みやすい形式にすることができます。
どういうわけか「悪」がプログラミング用語に忍び込んできました。誰が最初に落としたのか知りたいです。(実際、私は容疑者を持っています-彼はMITにいます。)私はむしろ、この分野での価値判断の客観的な理由があり、人々の好みや名前を呼ぶだけではありません。
場所があります。私は、開発者のスキルレベルがひどいものからウィザードのものまで、多くの企業で働いてきました。コードを維持する必要があり、私は永遠にそこにいないので、そこに属するように見えるように書きます(私のイニシャルでコメントを見ずに、あなたができることは非常にまれです変更した場所を確認するために作業したコードを見てください)、そして自分よりもスキルの低い人がそれを維持できることを確認してください。
三項演算子は素晴らしくて格好いいように見えますが、私の経験では、コードの行を維持するのはほぼ不可能です。私の現在の雇用主には、ほぼ20年間出荷されている製品があります。その例はどこにも使用しません。
最大の勝利:アクションのターゲットが1つであることを示します。
if ( $is_whatever )
$foo = 'A';
else
$foo = 'B';
フォローできるコードパスは2つあり、読者はどちらの変数が設定されているかを注意深く読む必要があります。この場合、変数は1つだけですが、読者はそれを理解するためにさらに読む必要があります。結局のところ、それはこれだったかもしれません:
if ( $is_whatever )
$foo = 'A';
else
$bar = 'B';
三項演算子を使用すると、設定されている変数が1つだけであることは明らかです。
$foo = $is_whatever ? 'A' : 'B';
最も低いレベルでは、最も基本的なのはDRY(Do n't Repeat Yourself)原則です。$foo
一度しか指定できない場合は、指定してください。
IMO、演算子自体は悪ではありませんが、C(およびC ++)で使用される構文は非常に簡潔です。IMO、Algol 60の方が優れていたため、次のようになりました。
A = x == y ? B : C;
次のようになります(ただし、一般にCのような構文に固執します)。
A = if (x==y) B else C;
それでも、過度に深いネストは読みやすさの問題につながる可能性がありますが、少なくともA)プログラミングを行った人なら誰でも簡単なものを理解でき、B)それを理解している人はかなり深いネストをかなり簡単に処理できます。OTOH、LISP(たとえば)では、a cond
は3項ステートメントに非常に似ています-ステートメントのセットではなく、値を生成する単一の式です(そして、LISPの大部分はそのようなものです。) )
A = (x==y) ? B : C
いつですか?:適切で、いつではないですか?
初心者に教えたり隠したりするべきですか?
重要ではありませんが、「初心者」が学習するのに複雑すぎないため、意図的に隠すべきではありません。
あなたの例では:
def median(a, b, c):
if a < b < c: return b
if a < c < b: return c
if b < a < c: return a
if b < c < a: return c
if c < a < b: return a
if c < b < a: return b
非常に読みやすく、明らかです。<<の間の変数は戻り値です。
同じですが、コードの行が少なくなります。まだシンプルだと思います。
def median(a, b, c):
if b<a<c or c<a<b: return a
if a<b<c or c<b<a: return b
if a<c<b or b<c<a: return c
constにも必要です
const int nLegs = isChicken ? 2: 4 ;
const
特定の言語ではそうだと思います。C#ではconst
、コンパイル時に既知の値を常に使用する必要があります。これは意味const int nLegs = isChicken ? 2: 4 ;
文句を言わない仕事を、しかしconst int nLegs = true ? 2: 4 ;
意志