私が知っている限り、いくつかはそうですが、人気のあるものはどれもありません。コメントをネストすることについて何か悪いことはありますか?
私が取り組んでいる(小さな)言語でブロックコメントをネストする予定ですが、これが悪い考えかどうかを知りたいです。
私が知っている限り、いくつかはそうですが、人気のあるものはどれもありません。コメントをネストすることについて何か悪いことはありますか?
私が取り組んでいる(小さな)言語でブロックコメントをネストする予定ですが、これが悪い考えかどうかを知りたいです。
回答:
誰もまだ言及していないことの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
ただし、ファイルの最後までコメントを開いたままにします(これもほぼ間違いなく構文エラーです)。したがって、どちらの方法でも、意図しない構文エラーが発生する可能性は特に低くなります。唯一の違いは、コメントアウトされたコードの意図的なアンチパターンを処理する方法です。
#if DEAD
は標準的かつ最適に設計された例です。多くの言語では、デッドコードをに相当するものでラップすることができますif (DEAD)
。また、多くのIDEでは、デッドコードを実際に削除し、必要に応じてCtrl + Zやバージョン管理に頼って元に戻すことができます。コメント、docstringなど、テキストが大量のデッドコードであるものを残すことは、読みやすさの点で依然として最悪の選択肢です。
実装のほとんどは、個別の字句解析および解析段階を使用しているため、字句解析には、従来の正規表現を使用しています。コメントは空白として扱われます。つまり、無視されたトークンであるため、字句解析パスで完全に解決する必要があります。このアプローチの唯一の利点は、解析速度です。多数の不利な点には、構文の厳しい制限(たとえば、固定された、コンテキストに依存しないキーワードのセットを維持する必要性)が含まれます。
ネストされたコメントを処理できるレクサーを作成することは完全に可能です。空白を食べているとき、それを見る/*
と、深度カウンターをインクリメントし、を見るとデクリメントし*/
、深度がゼロになると停止します。そうは言っても、私は多くのパーサーを実行しましたが、コメントをネストする正当な理由を見つけたことはありません。
コメントを入れ子にできる場合、欠点は簡単にバランスを崩してしまうことです。また、手の込んだエディターがない限り、そこにあると思われるコードを目に見えないように隠すことができます。
ネストしないコメントの利点は、次のようなものです。
/*
some code
more code
blah blah blah
/**/
最初の行を削除または追加することでコードを簡単にコメントインまたはコメントアウトできます-1行の編集。もちろん、そのコード自体にコメントが含まれている場合、C ++スタイルのコメントも許可しない限り、これは壊れます//
。だから私はそうする傾向があります。
//
コメントもC99スタイルです。
/*$token
、コメント開始が、identifier
が任意の英数字トークン、およびコメント終了がであると指定できますtoken$*/
。トークナイザーには、すべてのコメント終了マークに、それに対応するコメント開始ブロックの適切なトークンが含まれていることを確認するコードを含めるのは比較的簡単です。
ネストされたブロックコメントをサポートすると、パーサーが複雑になります。これは、より多くの作業であり、コンパイル時間を増加させる可能性があります。これは言語にとってあまり必要な機能ではないため、他の改善や最適化に時間と労力を費やす方が良いと思います。
私の意見では、シンプルさは何かを設計する上で常に良いことです。機能を削除するよりも追加する方が簡単であることに注意してください。ネストされたコメントを許可し、それを使用するプログラムがある場合、互換性を損なうことなくコメントを削除することはできません。
/*/**/
考えられる理由の1つは、レクサーで一般的に使用される正規表現のフレーバーは再帰をサポートしていないため、ネストされたコメントをパーサーで処理する必要があることです。単純なものは、レクサーによって空白として削除できるため、そのように実装する方が簡単です。
知るか?ネストされたコメントをサポートするのはより手間がかかるので、何らかのスタックを維持する必要があり、言語の文法が複雑になるためだと思います。
ネストされたコメントは、パーサーの追加作業を意味します。通常、コメントの開始が表示されるときは、コメント終了マーカーまですべてを無視します。ネストされたコメントをサポートするには、コメント内のテキストも解析する必要があります。ただし、最大の問題は、プログラマーがネストされたコメントをすべて正しく閉じるように注意する必要があることです。そうしないと、コンパイルエラーが発生します。コンパイラーを正しく実装することはできますが、プログラマーがネストされたコメントを追跡することは非常にエラーを起こしやすく、苛立たしいものです。