いくつかはありますが、私の知る限り、人気のあるものはありません。コメントのネストについて何か悪い点はありますか?
作業中の(小さい)言語でブロックコメントをネストする予定ですが、これが悪い考えかどうか知りたいのですが。
コメントをネストしたいという欲求は、プログラマが間違っていることを示していることがよくあります。
まず、プログラマーが「ネスト」または「ネストしない」ことを確認できるのは、プログラマーが次のような構造を書いているときだけであることに同意します。
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 */
*/
これはBADです。これは、(言語設計者として)私たちが奨励したいパターンではありません。上記のスニペットを記述する正しい方法は次のとおりです。
do_something(); /* do a thing */
その「間違った」コード、誤った開始、またはそれが何であれ、コードベースには属していません。せいぜい、ソース管理の歴史に属しています。理想的には、最初から間違ったコードを書くことさえないでしょう。そして、もし間違ったコードがそこに目的を果たしているならば、何らかの理由でそれを復元しないようにメンテナーに警告することによって、まあ、それはおそらくよく書かれた意図的なコードコメントの仕事です Xを実行する古いコードを残すだけで「Xを実行しない」を表現しようとするが、コメント化されている場合は、人々がXを実行しないようにするための最も読みやすいまたは効果的な方法ではありません。
これはすべて、以前に聞いたことのある簡単な経験則に要約されます。コードをコメント化しないでください。(このフレーズを検索すると、 lotofopinionsinagreement 。)
質問する前に:はい、C、C#、C++などの言語では、プログラマーに別のツールを提供して、コードの大きなブロックをコメント化します:#if 0
。しかし、これはCプリプロセッサの特定のアプリケーションにすぎません。これは、それ自体が大きくて便利なツールです。 #if
を使用した条件付きコンパイルをサポートし、さらに#if 0
をしないの言語をサポートすることは、実際には言語にとって非常に困難で特殊なケースです。
したがって、プログラマーがコードをコメント化している場合にのみ、ネストされたコメントが関連することを確認しました。そして、コードをコメントアウトすることは悪いことだと(多くの経験豊富なプログラマーのコンセンサスを介して)確立しました。
三段論法を完了するには、言語設計者が良いことを促進し、悪いことを阻止することに関心を持っていることを受け入れる必要があります(他のすべてが等しいと仮定します)。
ネストされたコメントの場合、他のすべてのは等しいです—ネストされた/*
の解析が何らかの理由で "難しい"と主張する投票の少ない回答を安全に無視できますパーサー。 (ネストされた/*
は、ネストされた(
と同じくらい簡単です。これは、世界中のほぼすべてのパーサーがすでに処理する必要があるものです。)
したがって、他のすべてが等しい場合、言語の設計者は、コメントをネストする(つまり、コードをコメント化する)ために簡単、または困難にする必要がありますか?コードをコメント化することは悪いことであることを思い出してください。
Q.E.D.
脚注。ネストされたコメントを許可しない場合は、
hello /* foo*/bar.txt */ world
誤解を招く「コメント」です—これは
hello bar.txt */ world
(これはおそらく構文エラーです)。しかし、doネストされたコメントを許可すると、
hello /* foo/*.txt */ world
誤解を招く「コメント」です—これは
hello
ただし、コメントはファイルの最後まで開いたままにしておきます(これもほぼ間違いなく構文エラーです)。したがって、どちらの方法でも、意図しない構文エラーが発生する可能性は特に低くなります。唯一の違いは、コメントアウトされたコードの意図的なアンチパターンの処理方法にあります。
ほとんどの実装は、別々の字句解析と解析の段階を使用しており、字句解析には、プレーンな古い正規表現を使用しています。コメントは空白として扱われます-つまり、無視されたトークンなので、字句解析パスで完全に解決する必要があります。このアプローチの唯一の利点は、解析速度です。多くの欠点には、構文に対する厳しい制限があります(たとえば、固定された、コンテキストに依存しないキーワードのセットを維持する必要がある)。
ネストされたコメントを処理できるレクサーを作成することは完全に可能です。空白を食べているときに/*
を検出すると、深度カウンターをインクリメントし、*/
を検出するとデクリメントし、深度がゼロになると停止します。そうは言っても、私は多くのパーサーを実行してきましたが、コメントをネストするための正当な理由を見つけられませんでした。
コメントがネストできる場合の欠点は、その結果のバランスが崩れやすく、ファンシーなエディターがない限り、そこにあると想定しているコードを非表示に隠すことができることです。
ネストしないコメントのメリットは次のとおりです。
/*
some code
more code
blah blah blah
/**/
最初の行を削除または追加することで、コードを簡単にコメントインまたはコメントアウトできます-1行の編集。もちろん、そのコード自体にコメントが含まれていると、これは機能しなくなりますnless C++スタイルの//
コメントも許可されます。だから私はそうする傾向があります。
他の誰もそれを言及しなかったので、ネストされたコメントをサポートするいくつかの言語をリストします:Rexx、Modula-2、Modula-3、Oberon。難易度と速度の問題についてのすべての苦情にもかかわらず、それらのどれも大きな問題を抱えているようには見えません。
ブロックコメントをネストすることの良い点は、コードの大部分を簡単にコメントアウトできることです(文字列定数にブロックコメントの終了シーケンスがない限り、ほとんどの場合)。
別の方法は、それをサポートするエディターがある場合、行コメントの開始シーケンスを行の先頭に追加することです。
Haskellにはブロックコメントがネストされていますが、ほとんどの人はそれに気づいたり、不満を言ったりすることはないようです。これは、他の言語では字句エラーになるため、ネストされたコメントを期待しない人はコメントを避ける傾向があるためだと思います。
ネストされたブロックコメントをサポートすると、パーサーが複雑になります。これは、より多くの作業であり、コンパイル時間が長くなる可能性があります。これは言語にとってそれほど必要な機能ではないので、他の改善や最適化に時間と労力を費やすことをお勧めします。
私の意見では、何でも設計する場合、単純さは常に良いことです。機能を追加する方が、削除するよりも簡単であることに注意してください。ネストされたコメントを許可し、それを使用するプログラムがあると、互換性を壊さずにコメントを取り出すことができなくなります。
考えられる理由の1つは、入れ子のコメントはパーサーで処理する必要があるためです。これは、レクサーで一般的に使用される正規表現の種類が再帰をサポートしていないためです。単純なものは、字句解析器によって空白として削除できるため、そのように実装するのは簡単です。
知るか?ネストされたコメントのサポートはより手間がかかるため、私は推測するでしょう。ある種のスタックを維持する必要があり、言語の文法が複雑になるためです。