ほとんどのプログラミング言語がブロックコメントをネストしないのはなぜですか?


18

私が知っている限り、いくつかはそうですが、人気のあるものはどれもありません。コメントをネストすることについて何か悪いことはありますか?

私が取り組んでいる(小さな)言語でブロックコメントをネストする予定ですが、これが悪い考えかどうかを知りたいです。


いくつかの答えについて:ああ、それは理にかなっています=)私は完全にネストされたブロックコメントをしています。個別の字句解析ステージがありますが、説明されている制限ソートSKロジックではありません。

@Vuntic:正規表現よりも複雑なものを使用する別のレキシングステージがある場合、パフォーマンスの問題が発生する可能性があります。REは、DFAを実装することにより、高速かつ簡単に使用できます。
デビッドソーンリー

ネストを許可しないために、より多くのエラーを早期にキャッチします

4
@David:...まったくありません。実際には本当に速いです。
アマラ

ネストされたコメントを許可する場合、コメントで開始タグをトークンでマークすることを許可し、コメント開始タグがこのようにマークされている場合、コメント終了タグも同じようにマークする必要があることをお勧めします。これにより、不均衡な開始/終了タグを迅速に識別でき、不均衡なタグが検出されないことに起因するバグの可能性を回避できます。
supercat

回答:


6

誰もまだ言及していないことの1つですので、私はそれについて言及します。コメントを入れ子にしたいという願望は、しばしばプログラマーが間違っていることを示しています。

まず、プログラマーが「ネスト」または「ネストしない」と表示されるのは、プログラマーが構造的に次のように記述したときだけであることに同意しましょう。

do_something();
/* comment /* nested comment */ more comment */
do_something_else();

さて、実際にそのようなことが起こるのはいつですか?確かに、プログラマーは、上記のスニペットのように文字通り見えるネストされたコメントを書くつもりはありません!いいえ、実際にコメントをネストする(またはネストできるようにしたい)とき、それは次のようなものを書きたいからです。

do_something();  /* do a thing */
/* [ajo] 2017-12-03 this turned out to be unnecessary
do_something_else(); /* do another thing */
*/

そして、これは悪いです。これは(言語デザイナーとして)奨励したいパターンではありません!正しい上記のスニペットを書くための方法は、次のとおりです。

do_something();  /* do a thing */

その「間違った」コード、その誤った開始、またはそれが何であれ、コードベースに属していません。せいぜい、ソース管理履歴に属します。理想的には、最初から間違ったコードを書くことさえないでしょうか?間違ったコードが目的を果たしていた場合、メンテナに何らかの理由でそれを回復しないように警告することで、それはおそらく、よく書かれた意図的なコードコメントの仕事ですXを実行する古いコードをコメントアウトするだけで「Xを実行しない」を表現しようとすることは、人々がXを実行できないようにする最も読みやすく効果的な方法ではありません。

これは、以前に聞いたことがあるかもしれない簡単な経験則に要約されます。コードをコメントアウトしないでください。(このフレーズを検索すると、多く 意見 一致します。)

あなたが尋ねる前に:はい、C、C#、C ++などの言語はすでに、プログラマーにコードの大きなブロックを「コメントアウト」するための別のツールを提供しています#if 0。しかし、これはCプリプロセッサの特定のアプリケーションに過ぎず、Cプリプロセッサはそれ自体が大きく有用なツールです。言語は条件付きコンパイルをサポートすることは、実際には非常に困難と特殊ケーシーとなり#if、まだありませんサポート#if 0


そのため、ネストされたコメントは、プログラマーがコードをコメントアウトしている場合にのみ関連することを確立しました。そして、多くの経験豊富なプログラマーのコンセンサスにより、コードをコメントアウトすることは悪いことだと確立しました。

三段論法を完了するには、言語デザイナーが良いことを促進し、悪いことを思いとどまらせることに関心があることを受け入れなければなりません(他のすべてが等しいと仮定して)。

ネストされたコメントの場合、他のすべて同じです。ネストされた構文解析/*は何らかの形でパーサーにとって「難しい」と主張する低投票の答えを無視してかまいません。(Nested /*は、nested (ほど難しくありません。nestedは、世界のほぼすべてのパーサーがすでに処理する必要があるものです。)

それで、他のすべてが平等である場合、言語設計者はコメントをネストする(コードをコメントアウトする)のを簡単にするの、それとも難しいのか? コードをコメントアウトすることは悪いことであることを思い出してください。

QED


脚注。ネストされたコメントを許可しない場合、

hello /* foo*/bar.txt */ world

は誤解を招く「コメント」です—これは次と同等です

hello bar.txt */ world

(これはおそらく構文エラーです)。しかし、あなたがあればやる、その後、ネストされたコメントを許可します

hello /* foo/*.txt */ world

は誤解を招く「コメント」です—これは次と同等です

hello

ただし、ファイルの最後までコメントを開いたままにします(これもほぼ間違いなく構文エラーです)。したがって、どちらの方法でも、意図しない構文エラーが発生する可能性は特に低くなります。唯一の違いは、コメントアウトされたコードの意図的なアンチパターンを処理する方法です。


1
私は単に事実に基づいて異なる意見を持っています-私はすべてを見ませんでした(そしてあなたも見ませんでした)。そのため、「コードをコメントアウトしない」などの黄金のルールは見栄えがよくなりますが、人生には独自の道があります。この特定のケースでは、新しい機能をテストし、コードを段階的に導入する必要があるときに、スイッチとして非常に頻繁にそれを行います。 (コード上で)すべてのコメントを削除できます。私の完璧な言語はもちろん、ネストされたコメントをサポートします:-)。
greenoldman

@greenoldman:ほとんどの言語にはネスト可能なコメントはありませんが、「コメントを残す」機能よりも使用頻度の低い「コードブロックを削除する」ための実際の機能があります。C #if DEADは標準的かつ最適に設計された例です。多くの言語では、デッドコードをに相当するものでラップすることができますif (DEAD)。また、多くのIDEでは、デッドコード実際に削除し、必要に応じてCtrl + Zやバージョン管理に頼って元に戻すことができます。コメント、docstringなど、テキストが大量のデッドコードであるものを残すことは、読みやすさの点で依然として最悪の選択肢です。
Quuxplusone

11

実装のほとんどは、個別の字句解析および解析段階を使用しているため、字句解析には、従来の正規表現を使用しています。コメントは空白として扱われます。つまり、無視されたトークンであるため、字句解析パスで完全に解決する必要があります。このアプローチの唯一の利点は、解析速度です。多数の不利な点には、構文の厳しい制限(たとえば、固定された、コンテキストに依存しないキーワードのセットを維持する必要性)が含まれます。


3
私は最近「ほとんど」に同意しません。確かにそれは伝統的な方法ですが、Cの場合、EDGはプリプロセッサ、字句解析、構文解析を組み合わせていることを知っています。GCCとMicrosoftの両方もそうだと思います。利点は、必要に応じて個別に実装できることです。
アンドリューエイレット

Clangも同じことをしています。しかし、それでも既存の一般的な言語コンパイラのごく一部にすぎません。
SKロジック

@Neil Butterworth、mcs、javac、gcc(うん、レクサーにパッチを当てますが、それでも専用の字句解析パスです)、clang(gccと同じ)、dmd、fpc、その他多数あります。
SKロジック

自明ではないコンパイラの字句解析で正規表現を使用している人はいません。
ヌージ

@Nuoji-自明ではない-確かに。しかし、flexや同様のツールに依存する人はそうします。
SKロジック

7

ネストされたコメントを処理できるレクサーを作成することは完全に可能です。空白を食べているとき、それを見る/*と、深度カウンターをインクリメントし、を見るとデクリメントし*/、深度がゼロになると停止します。そうは言っても、私は多くのパーサーを実行しましたが、コメントをネストする正当な理由を見つけたことはありません。

コメントを入れ子にできる場合、欠点は簡単にバランスを崩してしまうことです。また、手の込んだエディターがない限り、そこにあると思われるコードを目に見えないように隠すことができます。

ネストしないコメントの利点は、次のようなものです。

/*
some code
more code
blah blah blah
/**/

最初の行を削除または追加することでコードを簡単にコメントインまたはコメントアウトできます-1行の編集。もちろん、そのコード自体にコメントが含まれている場合、C ++スタイルのコメントも許可しない限り、これは壊れます//。だから私はそうする傾向があります。


1
//コメントもC99スタイルです。
JAB

あるいは、言語は/*$token、コメント開始が、identifierが任意の英数字トークン、およびコメント終了がであると指定できますtoken$*/。トークナイザーには、すべてのコメント終了マークに、それに対応するコメント開始ブロックの適切なトークンが含まれていることを確認するコードを含めるのは比較的簡単です。
supercat

5

誰もそれについて言及していないので、ネストされたコメントをサポートするいくつかの言語をリストします:Rexx、Modula-2、Modula-3、Oberon。ここでは難易度と速度の問題に関するすべての苦情にもかかわらず、それらのどれも大きな問題を抱えていないようです。


4
私が追加するもの:Haskell、Frege
Ingo

Scalaでもサポートされています。
マットR

4

ブロックコメントをネストすることの良い点は、コードの大部分を簡単にコメントアウトできることです(ほとんどの場合、文字列定数にブロックコメントの終了シーケンスがない限り)。

別の方法は、それをサポートするエディターがある場合、行コメント開始シーケンスを行の先頭に追加することです。

Haskellにはネストされたブロックコメントがありますが、ほとんどの人はそれに気づいたり文句を言ったりしないようです。これは、ネストされたコメントを期待していない人が、他の言語では字句エラーになるため、コメントを避ける傾向があるためだと思います。


3

ネストされたブロックコメントをサポートすると、パーサーが複雑になります。これは、より多くの作業であり、コンパイル時間を増加させる可能性があります。これは言語にとってあまり必要な機能ではないため、他の改善や最適化に時間と労力を費やす方が良いと思います。

私の意見では、シンプルさは何かを設計する上で常に良いことです。機能を削除するよりも追加する方が簡単であることに注意してください。ネストされたコメントを許可し、それを使用するプログラムがある場合、互換性を損なうことなくコメントを削除することはできません。


1
「削除するよりも機能を追加する方が簡単」の場合は+1。
R ..

3
ネストされたコメントを禁止したら、それは、このようなコメントを破るだろうからあなたにもそれを許可することはできません:/*/**/
リヤド

2

考えられる理由の1つは、レクサーで一般的に使用される正規表現のフレーバーは再帰をサポートしていないため、ネストされたコメントをパーサーで処理する必要があることです。単純なものは、レクサーによって空白として削除できるため、そのように実装する方が簡単です。


3
それは「味」ではありません。正規表現の「正規」という言葉は、本質的に再帰を除外します。
R ..

3
@R:数学では、確かに。しかし、プログラミングでは、再帰をサポートする正規表現と呼ばれるものがあります。
アマラ

問題は、これも問題ですか?ほとんどの言語は、すでにネストされた括弧を処理する必要があります。Lisp、C、Java、Python、Ruby、Perlなどの名前を付けます。
トーマスエディング14

入れ子になったかっこは問題ありません。かっこの中は外部のものと同じであるため、通常のトークンです。コメントには、トークンはなく、テキストだけがあります。「int」がタイプであるか、コメント内の単なる単語であるかを知るために、開始コメントトークンと終了コメントトークンを一致させる必要があります。(特にレクサーのコメントを削除する場合。)
アランシュトコ14年

2
@ThePopMachine:私が述べたことは確かです、レギュラーはあなたが使用している意味ではなく、定義された正式な意味を持ち、「正規表現」の「正規」がこの意味のために選ばれました。非再帰的であることは、その定義の1つの結果です。
R .. 14年

-1

知るか?ネストされたコメントをサポートするのはより手間がかかるので、何らかのスタックを維持する必要があり、言語の文法が複雑になるためだと思います。


-1

ネストされたコメントは、パーサーの追加作業を意味します。通常、コメントの開始が表示されるときは、コメント終了マーカーまですべてを無視します。ネストされたコメントをサポートするには、コメント内のテキストも解析する必要があります。ただし、最大の問題は、プログラマーがネストされたコメントをすべて正しく閉じるように注意する必要があることです。そうしないと、コンパイルエラーが発生します。コンパイラーを正しく実装することはできますが、プログラマーがネストされたコメントを追跡することは非常にエラーを起こしやすく、苛立たしいものです。


3
-1:正しくない。正常なパーサーはそのようには機能しません。
アマラ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.