C、Java、C++などの言語では、if
、while
、またはswitch
で使用する場合、式全体を括弧で囲む必要があります。
if (true) {
// Do something
}
とは対照的に
if true {
// Do something
}
括弧が冗長であるため、これは私には奇妙に思えます。この例では、true
はそれ自体が単一の式です。括弧は、私が知っている方法でその意味を変換しません。なぜこの奇妙な構文が存在し、なぜそれほど一般的であるのですか?私が知らないことの利点はありますか?
some条件がどこで終了して分岐が始まるかを伝える方法が必要です。それには多くの異なる方法があります。
一部の言語では、条件がまったくありません。 Smalltalk、Self、Newspeak、Io、Ioke、Seph、およびFancyで。条件付き分岐は、他のメソッドと同様に、通常のメソッドとして実装されます。このメソッドはbooleansオブジェクトに実装され、booleanで呼び出されます。このように、条件は単にメソッドのレシーバーであり、2つのブランチは2つの引数です。 Smalltalk:
aBooleanExpression ifTrue: [23] ifFalse: [42].
Javaに慣れている場合、これは次と同等です。
aBooleanExpression.ifThenElse(() -> 23, () -> 42);
LISPファミリの言語では、状況は似ています。条件は単なる通常の関数(実際にはマクロ)であり、最初の引数は条件で、2番目と3番目の引数は分岐です。したがって、これらは通常の関数引数であり、それらを区切るのに特別なことは何も必要ありません:
(if aBooleanExpression 23 42)
一部の言語では、キーワードを区切り文字として使用しています。 ALGOL、Ada、BASIC、Pascal、Modula-2、Oberon、Oberon-2、Active Oberon、Component Pascal、Zonnon、Modula-3:
IF aBooleanExpression THEN RETURN 23 ELSE RETURN 42;
Rubyでは、キーワードまたは式の区切り文字(セミコロンまたは改行)を使用できます。
if a_boolean_expression then 23 else 42 end
if a_boolean_expression; 23 else 42 end
# non-idiomatic, the minimum amount of whitespace required syntactically
if a_boolean_expression
23 else 42 end
# idiomatic, although only the first newline is required syntactically
if a_boolean_expression
23
else
42
end
Go はブランチをブロックにする必要があり、式やステートメントを許可しないため、中括弧が必須になります。したがって、必要に応じて括弧を追加できますが、括弧は必要ありません。 Perl6とRustはこの点で似ています:
if aBooleanExpression { return 23 } else { return 42 }
一部の言語では、他の非英数字を使用して条件を区切ります。 Python:
if aBooleanExpression: return 23
else: return 42
一番下の行は、条件が終了して分岐がどこで始まるかを伝えるsome方法が必要です。そうする方法はたくさんありますが、括弧はその1つにすぎません。
括弧は、中括弧を使用する場合にのみ必要です。
if true ++ x;
たとえば、それらがなければあいまいになります。
if
ステートメントの括弧は、算術式内で使用される括弧と同じ意味を持ちません。算術式の括弧は、式をグループ化するために使用されます。 if
ステートメントの括弧は、ブール式を区切るために使用されます。つまり、ブール式を残りのif
ステートメントと区別するためです。
if
ステートメントでは、括弧はグループ化機能を実行しません(ただし、if
ステートメント内では、括弧を使用して算術式をグループ化できます。次に、括弧の外側のセットは、ブール式全体)。必要なものにすることで、コンパイラーは単純化されます。これは、コンパイラーが括弧が常に存在していることに依存できるためです。
他の人がすでに部分的に指摘しているように、これは式も有効なステートメントであり、ステートメントが1つだけのブロックの場合は中括弧を削除できるという事実によるものです。これは、以下はあいまいであることを意味します。
if true
+x;
これは次のように解釈できるためです。
if (true + x) {}
の代わりに:
if (true) {+x;}
多くの言語(Pythonなど)では、かっこを回避できますが、終了条件マーカーがあります。
真であれば: + x
ただし、couldかっこが不要な言語を定義するのは正しい:式がnotである言語は、有効なステートメントではこの問題は発生しません。
残念ながら、これは次のようなことを意味します。
++x;
functionCall(1,2,3);
notは有効なステートメントなので、式を作成せずにそのようなアクションを実行できるようにするには、奇妙な構文を導入する必要があります。これを行う簡単な方法は、[statement]
のようなマーカーを式の前に付けるだけです。
[statement] ++x;
[statement] functionCall(1,2,3);
次のように記述する必要があるため、あいまいさがなくなります。
if true
[statement] ++x;
しかし、あなたが見ることができるように、if
- condition(または最後に:
)をかっこで囲むことは、すべての式ステートメントにそのようなマーカーを置くよりもはるかに良いので、そのような言語が広まっているとは思えません。
注:[statement]
マーカーの使用は、私が考えることができる最も単純な構文です。ただし、couldには、式とステートメントに2つの完全に異なる構文があり、そのようなマーカーを必要としないあいまいさはありません。問題は、式やステートメントで同じことを行うには、まったく異なる構文を使用する必要があるため、言語が非常に奇妙になることです。
たとえば、そのような明示的なマーカーがない2つの個別の構文があることを思い出すと、たとえば、Unicode記号を使用するようにステートメントを強制します(つまり、for
の代わりに、f
、o
、r
のUnicodeバリエーションを使用します)。一方、式はASCIIのみとなります。
Cファミリ言語では、これらの括弧が必要になるのが一般的ですが、普遍的ではありません。
Perl 6のより顕著な構文上の変更の1つは、if
、for
および同様のステートメントの条件を括弧で囲む必要がないように文法を変更したことです。したがって、このようなものはPerl 6で完全に有効です。
if $x == 4 {
...
}
そのまま
while $queue.pop {
...
}
ただし、これらは単なる式であるため、必要に応じて括弧を付けることができます。その場合、C、C#、Javaなどのように、構文の必須部分ではなく、通常のグループ化の括弧になります。
Rustの構文は、この部門のPerl 6と似ています。
if x == 4 {
...
}
より現代的なCに触発された言語の特徴は、このようなものを見て、それらを削除することについて疑問に思うことです。
既存の答えのどれも持ち出していないことに私が驚いた一面があります。
C、および多くのCの派生物とそっくりさんには、次のような特徴があります割り当ての値は割り当てられた値ですこれの結果は割り当ては、値が必要です。
これにより、次のようなものを書くことができます
_if (x = getValue() == 42) { ... }
_
または
_if (x == y = 47) { ... }
_
または
_unsigned int n = 0 /* given m == SOME_VALUE */;
while (n < m && *p1++ = *p2++) { n++; }
_
(Cはゼロ以外をtrueとして扱うため、これは暗黙的にwhile (n < m && *p1++ = *p2++ != 0) { n++; }
として扱われます。ちなみに、C標準ライブラリのstrncpy()についてだと思います)
あるいは
_if (x = 17);
_
そしてそれはすべて有効です。すべての構文的に有効な組み合わせが必ずしも有用であるとは限りません(そして、最近のコンパイラは一般的なエラーであるため、条件文内の割り当てについて特に警告します) 、しかしいくつかは実際に役立ちます。
条件式がどこで始まりどこで終わるかを決定する明確な方法がなければ、そのようなステートメントの解析ははるかに困難になるでしょう。
関数の引数から関数名を区切るために括弧がすでに使用されていたので、キーワード引数からキーワードを区切るのも自然な選択のように思われたと思います。
もちろん、別の構文を定義して同じことを行うこともできます。ただし、そうすると、特にパーサーで複雑さが増し、ほとんど同じものに対して2つの異なる構文セットを処理する必要があります。 Cが設計されていた頃は、計算能力(数値処理能力、ワーキングメモリ、ストレージ容量の両方)は非常に制限されていました。読みやすさをほとんどまたはまったく犠牲にせずに複雑さを軽減するものは、ほぼ間違いなく歓迎すべき変更でした。
かっこを使用すると、今日は少し古風に思えるかもしれませんが、言語にある程度の知識がある人にとっては、同じことを表現できる他の構文に比べて読みやすさが損なわれます。
その理由は主に歴史です。
最初のCコンパイラが作成された時点では、コンピュータは非常に限られたram、cpu、コンパイラを備えており、コンパイラの作成者を支援するツールがほとんどなく、「手動」で作成されています。したがって、コンパイラに実装するには複雑なルールにはコストがかかりました。 C++、C#、Javaなどはすべて、Cプログラマーが学習しやすいように設計されていますしたがって、「不要な」変更は行われませんでした。
「cのような」言語では条件文(if, while, etc
)明示的なblock
offコードを必要とせず、単純なステートメントを使用できます。
if (a == d) doIt()
または、ステートメントを組み合わせてcompound statement
を{}
コンパイラーは、発生したエラーを見つけて、理解できるエラーメッセージとして表示することを望んでいます。
ここでの多くの理由は、括弧がないと構文が曖昧であり、これが何らかの形で悪いか、あるいは不可能な状況であることを暗黙のうちに示唆しているためです。
実際、言語にはあいまいさを処理する多くの方法があります。演算子の優先順位は、このトピックの1つの例にすぎません。
いいえ、あいまいさは括弧の理由ではありません。条件の周りに括弧を必要としない(したがってそれらをオプションにする)Cのバージョンを作成するだけで、すべてのケースで有効なコードを作成できると思います。 _if a ++ b;
_の例は、if (a) ++b;
またはif (a++) b;
と同等であると解釈できます。
Dennis Ritchieがなぜ()を必須にすることを選んだのか(したがって、多くの派生言語に対してこのミームを作成したのか)の問題は、むしろ言語的なものです。条件がcommandではなくexpressionであることを明確に述べるという考えは、思考の父であったと思います。
そして実際、Cはワンパスパーサーを使用して解析できるように設計されています。条件を括弧で囲む構文を使用すると、この側面がサポートされます。
JavaとC++はどちらも、Cが非常に人気のあるプログラミング言語になった後に開発されました。これらの各言語の設計における考慮事項の1つは、Cプログラマに魅力を感じさせ、新しい言語を使用するようにそれらのプログラマに懇願することでした。 (私は彼らが成功したCプログラマーの1人でした。)C++はさらに、(ほとんど)Cコードと交換できるように設計されました。これらの目標をサポートするために、C++とJavaはどちらも、if
、while
、switch
ステートメントの条件を囲む括弧を含む、Cの構文の多くを採用しました。
したがって、これらのすべての言語がそれらのステートメントの条件の前後に括弧を必要とするのはCがそうするためであり、問題は、Cがこれらの括弧を必要とする理由です。
C言語の起源は この開発の主要な著者の1人であるDennis Ritchieによるこの記事 (theその開発の主要な著者)。その記事で述べたように、Cはもともと1970年代初頭にメインメモリのスペースが非常に限られたコンピュータ用のシステムプログラミング言語として開発されました。アセンブリ言語よりも高水準の言語が望まれていましたが、使用できるリソースがあるため、言語の解析のしやすさも重要でした。括弧が必要な場合は、条件付きコードを比較的簡単に識別できます。
より少ない文字を使用してプログラムを作成する機能は利点と見なされ、2つの括弧は、当時FORTRANおよび他の高水準言語で使用されていたキーワードTHEN
よりもスペースが少ないと推測する人もいます。実際、括弧は記号の区切り文字としてスペースを置き換えることもできるため、if(a==b)
はIF a==b THEN
よりも4文字短い文字でした。
いずれにしても、Cで書かれたプログラムを人間がどれほど簡単に読み取り、書き込み、理解できるか、コンパイラーがCで書かれたプログラムをどれだけ簡単に解析およびコンパイルできるか、および何キロバイト(!)プログラムソースとコンパイラ自体の両方に必要です。そして、if
、while
、およびswitch
ステートメントの条件を囲む括弧は、Cの設計でそのバランスをとることを選択した方法です。
他のいくつかの回答で証明されているように、Cが開発された特定の状況を取り除くと、さまざまな種類の構文がさまざまなプログラミング言語の条件に使用されています。したがって、括弧は実際には、歴史上の特定の時間に特定の制約の下で数人の人々が行った設計上の決定に帰着します。
Fortran、Cobol、PL/1、ALGOL、Algo-68、Pascal、Modula、XPL、PL/M、MPLなどのif
キーワードを持つ言語では、then
条件を囲む括弧は不要です。 then
は、condition
を次のstatement
から区切る働きをします。
Cなどの右括弧はthen
として機能し、左括弧は形式的に冗長です。
上記の説明は、伝統的に解析される言語に適用されます。