なぜ未使用の変数がそのような問題なのですか?


9

ある日、未使用の変数の警告を消去していましたが、熟考し始めました。それらの問題は何ですか?

実際、それらの一部はデバッグにも役立ちます(例:例外の詳細を調べる、または返される前に戻り値を確認する)。

私はそれらを持っていることで本当の実際のリスクを見つけることができませんでした。

次のような他のプログラマーの注意を引く時間がかかる行を意味するのではありません。

int abc = 7;

それは明らかな冗長性と注意散漫です。私は次のようなものを意味します:

try {
    SomeMethod();
} catch (SomeException e) {
    // here e is unused, but during debug we can inspect exception details
    DoSomethingAboutIt();
}

31
あなたがあなたの後に来るプログラマーが彼らがなぜそこにいるのかを理解するために時間を費やさなければならないという事実以外にあなたは意味しますか?
ロバートハーベイ


1
あなたの例は無害ですが、「未使用の変数」と呼ばれるようなケースを見たことはありません。警告はどこから来ていますか?
Jacob Raihle 2017年

9
さて、ret未使用ではありません。
ロバートハーベイ

4
あなたは「私は次のようなものを意味し ます」書きましたcatch (SomeException e)-あなたは他の同様のケースがあると偽っています。私を啓発してください C#またはC ++では、ケースの別の状況を見つけるのに苦労しているので、質問します。
Doc Brown

回答:


4

あなたが与えた枠組みによれば、それらの変数自体に反対することは難しいです:

try {
    SomeMethod();
} catch (SomeException e) {
// here e is unused, but during debug we can inspect exception details
DoSomethingAboutIt();
}

これを例にとります。あなたは例外をキャッチしていて、(おそらく)適切な方法で例外を処理するコードを持っています。例外の実際のインスタンスを使用していないという事実は、コードフローにも理解可能性にも害を及ぼしません。

しかし、私が考えるのは、「未使用の変数」の合法化について書いているときです。

実際、それらのいくつかはデバッグにも役立ちます

それはコードを書く目的ではなく、後でデバッグする必要があります。誤解を防ぐために、私はよく承知していることですが、コードを修正する必要があることもよくあります。時にはデバッグが解決策です。しかし、コードを作成するときに、「アンカーポイント」を残すのは最初のことではありません。その目的は、デバッグを容易にすることだけです。

SomeClass Func() {
    // ...stuff...
    var ret = FinalComputationResult(thing, foo, bar);
    // ret is unused, but while debugging allows checking return value.
    return ret;
}

ここでは、それがどの程度複雑でstuffあるか、そしてそれがどのように返される値に関連しているかによって異なります。

「ゴールデンルール」として、私は次のように言います。

コードの目的を理解するのに役立つ場合は、コードの冗長性を停止しても問題ありません。

またはそれ以外の場合:

コードが何をしているかを後で簡単に理解するために必要なだけ冗長性のないコードを記述します

その結果、ほとんどの場合、「デバッグ」変数を削除する必要があります


19

最大の問題は明快さです。あなたのコードに無関係なジャンクがたくさんあり、私があなたのコードを維持しているなら、私はすべてが何をしているのかを理解しなければなりません。

その変数は何かに使用されたことがありますか?おそらくそれに対して操作を実行しますが、その値を何かに使用することはありません。変数を単にインクリメントしても、それを一度も読み取らなかった場合(戻り、別の式への入力など)に変数が目的を果たすということにはなりません。

ただし、変数に目的があり、適切名前が付けられている場合、コード全体を損なうことはありませ

あなたの更新された質問の例と私が考えたいくつかの他のものを考えると:

  • 別の関数を呼び出して結果を保存し、ログに記録してから返す関数があると、かなり短くて明確になります。

  • 複数の式を持つステートメントを複数のステートメントに分割する(たとえば、長くて複雑な計算を複数の中間変数を持つ複数のステートメントに分割する)と、コードはより冗長になりますが、より明確になります。一度に処理する情報が少ないと、脳はより簡単に何が起こっているのかを理解できます。

  • 例外を使用しなくても問題ありません。ほとんどの言語では、catchブロックで使用する変数名を指定するなど、キャッチする例外を指定する必要があります。多くの一般的な言語ではこれを回避する方法はなく、プログラマーはそれに慣れています。

どのコード要素に目的があり、どれが私の時間を無駄にしているのかを理解するのに時間を費やす必要がある場合、私の生産性は低下します。ただし、コードがかなり簡潔で、最初は無関係であるように見えても変数に適切な名前が付けられている場合は、コードを確認して理解するために不必要な時間を浪費するリスクが軽減されます。

無関係な変数、空のブロック、デッドコードを含む不良コードは、開発者がオフィスで悪い評判を得るための1つの方法です。バグ!雪だるまはプログラミングがひどい!」しかし、コードが目的を果たし、明確な方法で書かれている場合、それは完全に問題ありません。


9
+1「スノーマンはプログラミングがひどい」私はいつも疑っていました。指が常に溶けているときに、どうすれば良いプログラマーになれますか?
ロバートハーベイ

私の編集を参照してください-私が目的外に突然作成した単なる変数ではなく、デバッグ中にあちらこちらで役立つ変数や、catchブロックなどの自動ツールの1つによって生成された変数だけを意味します。
Tar

1
質問全体を変更する@Tar-着信を編集します。

これを行うときの箇条書きのリストでは、最初の2つは実際には警告にならない傾向があることに注意してください(そのような場合に警告を生成する言語を見たことがありません)。3番目のケースでは、識別子を指定することを例外として必要とする言語には警告がありません。警告を生成する言語には、識別子を必要としません(ここでも、とにかく)。
サービー

2
改訂履歴を見ると、質問が根本的に変化している兆候は見られません。OPのコードに関する限り、最初の2つはC#で警告になります(これは使用されている言語のようです)。3番目の例では警告は発生しません。質問へのコメントは、コンパイラの警告に具体的に示されていることも示しています。ロバートが3番目の例では警告を生成しないと指摘したとき、著者はそれが質問の悪い例であることを認めました。
サービー

5

明白な目的を果たさない未使用の変数は、私の見解ではコードのにおいです。せいぜい、それらは気を散らすものになる可能性があります-それらはモジュールの一般的なノイズに追加されます。

最悪のケースは、後続のコーダーが何をすべきかを理解し、コードが完全であるかどうか疑問に思っている時間を費やすことです。自分自身(そして他のすべての人)に好意を示し、取り除きます。


1
あなたの見解における「バグ」とは何ですか?未使用の変数は、それ自体が予期しない誤った結果を生み出すことはありません。これは、ほとんどの人がバグとみなすものです。
Harris

5
変数が使用されないのはなぜですか?おそらく使用されたはずですが、誤って別の変数が使用されました。コンパイラの警告が表示され、それを修正すると同時にバグを修正します。問題は、混乱している無規律なプログラマがいる場合、その種の警告がバグを示している場所と、乱雑なプログラマを示している場所を見つけることができないことです。
gnasher729 2017年

@HarrisWeinsteinテスターや開発者は、ほとんどの場合バグが何であるかに同意することさえできないので、とりあえずここに置きます。それはコードの欠陥であると言うだけで十分です-そしてそれはそれがスペースを取るので実行可能ファイルです。確かに、世界で最大の問題ではありませんが、コメントボックスのスペルミスとコードのコメントアウトで問題が発生しています。何も追加されないので、削除する必要があります。見栄えの良いコードは自信を呼び起こします。この見積もりも適切で、リファクタリングプロセスを適切にカバーしていると思います。
ロビーディー

動的言語を使用しているsome_var場合、残りのコードが使用するときに値を割り当てることsomeVarは、ほぼ間違いなくバグです。これはJavaまたはCでは問題にならないかもしれませんが、一部のPythonを簡単に破壊する可能性があります。
ショーンマクサムシング2017年

1
@ThomasJunkそれはおそらくより良い言葉です-ありがとう。私はそれに応じて私の答えを調整します。
ロビーディー

5

未使用の変数は、コードの意図を不明確にします。外見にもかかわらず、コードは主にコンピューターではなく、読む人のために書かれているため、これは悪いことです

他の人は、値を作成してそれを使用しないと、コードを読んで作業しなければならない他の人を混乱させることをすでに指摘しています。しかし、私の見解では、より大きな危険は自分自身にあります

未使用の変数は意図的なものである場合と、欠陥を指摘する見落としである場合があります。たとえば、名前を間違って入力し、別の場所に値を格納したと思ったときに値を格納した可能性があります。結果のプログラムは問題なく実行できますが、静かに間違った結果を出します。

データフローを分析すると、そのようなエラーや他の多くのエラーを見つけるのに役立ちます。したがって、データフローアナライザーが異常として指摘するすべてのものが実際にはバグであるような方法でコードを記述することは価値があります。バグを防ぐための自動支援は非常に貴重です。多くの人は「ああ、私は援助を必要としないので、私は不注意になることは決してないだろう」と思っていますが、今のところ私が会ったすべての人はそれが間違っていると思っていました。


2

デバッガーで変数を簡単に確認するという特定の目的のために、関心のある(または関心を持つ可能性のある)変数を意図的に変数に割り当てるコーディングスタイルがあります。これは、次のようなコードに特に役立ちます。

return foo(bar(), baz(wot(12), wombat(&badger)));

関数の名前がいくらか優れていても、次のように記述すると、fooの呼び出しで問題が発生している箇所を簡単に特定できます。

auto awombat = wombat(&badger);
auto awot = wot(12);
auto abaz = baz(awot, abadger);
auto abar = bar();
auto afoo = foo(abar, abaz);
return afoo;

私はこれをデフォルトの構成として実践している人々とはまだ協力していませんが、頑強に拒否して単一の割り当て形式で意味をなさないコードを書き直すと、デバッガーで何が起こっているのかを簡単に理解できるようになります。その後は常にコードをコンパクトな「きれいな」形式に戻しましたが、それが間違いだったのかと思います。

代わりの方法は、スタックを上下に移動し、あまり遠くに行かないことを期待するか、または(悲惨なことにまれに)リバーシブルデバッガーを使用することです。

それは人気のある戦略ではありませんが、いくつかの不条理なバグを解決するのに役立つので、本質的に悪いと見なされるべきではないと思います。


私はおそらくあなたのところまで行きませんが、あなたの最初の「きれいな」形はコンパクトすぎると思います。
Loren Pechtel 2017年

ただし、コードには未使用の変数が1つもありません。
フロリアンF

良い面としては、未使用の変数に関する警告が表示された場合、その変換のどこかで大失敗を犯したことがわかるでしょう。これは簡単に修正できます。
gnasher729 2017年

1

ユニットテストコードを「実際の」コードと同じプロジェクトまたはモジュールに含める場合、オブジェクトメソッドなどの未使用フィールドは、ユニットテストがすべてをテストしているわけではないことを強く示しています。これにより、開発者が現在未使用のフィールドまたはメソッドを使用しようとする可能性が高まり、それまで検出されなかったバグに遭遇します。

あまり重要ではないサブルーチンまたはメソッドで未使用の変数は、プログラマがそれを使用するつもりであったが、誤って別の変数を使用していることを示している可能性があります(たとえば、コピー/貼り付け操作後のクリーンアップ後)。

他の人が答えたように、より平凡なサブルーチンで使用されていない変数はおそらく不要なドロスです。時々、現在コメントアウトされているブレッドクラムステートメントで使用されます。

SomeObject tmp = someMethod();
// printDebugInfoAbout (tmp);

...それがそこで使用され、そこだけである(つまりsomeMethod、重要な副作用がある)ことは明らかですが、IDEはそれを認識していません。その変数を削除することは、その価値よりも厄介です。そんな時は暫定的に警告サプレッサーを使っています。


1
リポジトリにコミットされたコードをどのような状況でコミットしたいのでしょうか。ただし、条件付きコンパイルを使用する場合(assertCまたはC ++でマクロを使用する場合など)にも同様の状況が発生します。未使用の変数の警告は確かにそこに不快感を与える可能性があり、私に尋ねた場合、それらを抑制することが最も合理的な応答です。
5gon12eder 2017年

1
私は自分の回答を編集して、過去に見た非常に大まかな例を追加しました。ブロックは何度も実行される可能性があり、問題を追跡するときに、何かがログのすべてのデバッグ情報を分析のために収集していますが、印刷が遅いため、通常はオフになっています。最初の行をに置き換えて、someMethodどこtmpから来たかに関する情報を失う可能性があります。または、クリーンなバージョンをコミットして、過去のバージョンの一部にその便利なブレッドクラムがあったことを忘れることができました(それ以降のバージョンでは必要なコードが追加されていませんでした)。...私は長い間、これについて理想的なトレードオフを求めてきました。
ポールブリンクリー2017年

そうですか。どうやら、あなたの選択した言語にはプリプロセッサがありません。;-)
5gon12eder 2017年

現在、アイ。:-)公平を期すために、CとC ++でこれと同じ種類のものを見たことがあります。同様に、これらの場合にも未使用の変数を取り除くのは簡単ではありませんでした(準付録?)。...私の最後の大きなC / C ++プロジェクトがIDEが存在しないときに行われたという事実( "gcc -pedantic"の実行が必要なコンパイラの警告)も役に立ちませんでした。
ポールブリンクリー2017年

0

2つの変数を混在させるコードを記述する場合は簡単です。変数Bを計算しますが、代わりに以前に作成した変数Aを使用します。

したがって、未使用の変数の考えられる理由は、コードに誤りがあることです。コンパイラが警告するのはそのためです。未使用の変数を「行わない」場合、それは完全に無料のプレゼントです。

このような警告が表示された場合は、コードを確認して修正するか、問題のある変数を削除する必要があります。削除しないと、これらの警告に注意を払うのをやめ、完全に無効にすることもできます。しかし、その後、1つのばかげた間違いのために、コードのデバッグを午後に失うことになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.