特定のコンテキストで、min関数とmax関数について混乱します。
1つのコンテキストでは、関数を使用して2つの値の多かれ少なかれ取る場合、問題はありません。例えば、
//how many autographed CD's can I give out?
int howManyAutographs(int CDs, int Cases, int Pens)
{
//if no pens, then I cannot sign any autographs
if (Pens == 0)
return 0;
//I cannot give away a CD without a case or a case without a CD
return min(CDs, Cases);
}
簡単です。しかし、別の状況では、私は混乱します。最大値または最小値を設定しようとしている場合、逆方向に取得します。
//return the sum, with a maximum of 255
int cappedSumWRONG(int x, int y)
{
return max(x + y, 255); //nope, this is wrong
}
//return the sum, with a maximum of 255
int cappedSumCORRECT(int x, int y)
{
return min(x + y, 255); //much better, but counter-intuitive to my mind
}
自分の機能を次のようにすることはお勧めできませんか?
//return x, with a maximum of max
int maximize(int x, int max)
{
return min(x, max);
}
//return x, with a minimum of min
int minimize(int x, int min)
{
return max(x, min)
}
明らかに、ビルトインを使用する方が高速ですが、これは私にとっては不要なマイクロ最適化のようです。これがお勧めできない他の理由はありますか?グループプロジェクトではどうですか?
他の人がすでに述べたように、組み込み関数、標準ライブラリ関数、または一般的に広く使用されている関数の名前に似た名前で関数を作成しないでください。ただし、その動作を変更してください。一見して意味がわからなくても命名規則に慣れることは可能ですが、同じことを行う他の関数を導入すると、コードの機能について推論することは不可能になります彼らの名前は入れ替わった。
標準ライブラリが使用する名前を「オーバーロード」する代わりに、意味を正確に伝える新しい名前を使用してください。あなたの場合、あなたは「最小」に本当に興味がありません。むしろ、値をcapしたいとします。数学的には、これは同じ操作ですが、意味的には、完全ではありません。では、なぜ関数ではないのか
int cap(int value, int limit) { return (value > limit) ? limit : value; }
それは必要なことを行い、その名前からそれを伝えます。 ( timster 's answer に示すように、cap
のmin
inを実装することもできます)。
よく使用されるもう1つの関数名はclamp
です。 3つの引数を取り、提供された値を他の2つの値で定義された間隔に「クランプ」します。
int clamp(int value, int lower, int upper) {
assert(lower <= upper); // precondition check
if (value < lower) return lower;
else if (value > upper) return upper;
else return value;
}
このような一般的に知られている関数名を使用している場合、チームに参加する新しい人(しばらくしてからコードに戻ってくる将来を含む)は、混乱させて混乱させるのではなく、何が起こっているのかをすぐに理解できます。彼らが知っていると思った関数名についての期待。
minimize(4, 10)
が1を返すような関数を作成する場合、他のプログラマーが首を絞める可能性があるため、これはお勧めできません。
(さて、多分彼らは文字通りあなたを死に至らしめるのではなく、真剣に...それをしないでください。)
関数のエイリアスは問題ありませんが、既存の用語の意味を変更しないでください
関数のエイリアスを作成することは問題ありません-共通ライブラリ 常にそれを行います 。
ただし、最大値と最小値を反転させる必要がある例のように、一般的な使用法とは逆の方法で用語を使用することはお勧めできません。これは他のプログラマーを混乱させるものであり、これらの用語を非標準的な方法で解釈し続けるように自分自身を訓練することによって、自分自身を害することになります。
したがって、あなたのケースでは、混乱を招く「最小/最大」の用語を放棄し、独自の理解しやすいコードを作成してください。
あなたの例をリファクタリングする:
int apply_upper_bound(int x, int y)
{
return min(x, y);
}
int apply_lower_bound(int x, int y)
{
return max(x, y)
}
追加のボーナスとして、このコードを見るたびに、minおよびmaxはプログラミング言語で使用されます。最終的に、それはあなたの頭の中で理にかなってくるでしょう。
この質問が大好きです。それを分解しましょう。
1:1行のコードをラップする必要がありますか?
はい、あなたがこれを行うかもしれない多くの例を考えることができます。型付けされたパラメーターを適用したり、インターフェースの背後にある具体的な実装を隠したりしている可能性があります。あなたの例では、基本的に静的メソッド呼び出しを隠しています。
さらに、最近では1行で多くのことを行うことができます。
2:「Min」と「Max」の名前はわかりにくいですか
はい!彼らは完全にです!クリーンなコーディングの達人は、それらの名前を「FunctionWhichReturnsTheLargestOfItsParameters」などに変更します。幸いなことに、私たちはドキュメントと(運が良ければ) IntelliSense とコメントを用意してくれているので、名前に混乱している人は誰でも何をすべきかを読むことができます。
3:自分で別の名前に変更する必要があります。
うん、それのために行きます。たとえば、次のようにすることができます。
class Employee
{
int NumberOfHolidayDaysIShouldHave(int daysInLue, int maxAllowableHolidayDays)
{
// Return the number of days in lue, but keep the value under the max allowable holiday days!
// Don't use max, you fool!!
return Math.Max(daysInLue, maxAllowableHolidayDays)
}
}
これは意味を追加し、呼び出し元は値を計算する方法を知っている必要はありません。
4:「min」の名前を「maximize」に変更する必要があります
いいえ!!クレイジーですか?!しかし、はい、質問によって、関数やオブジェクトの名前の意味が人によって異なるという点が強調されています。ある人が明確であり、慣習的であると感じるものは、不透明で混乱します。そのため、コメントがあります。代わりに次のように書く必要があります:
// Add x and y, but don't let it go over 255
s = min(x + y, 255);
次に誰かが読んだとき
// Add x and y, but don't let it go over 255
s = max(x + y, 255);
彼らはあなたが間違いをしたことを知っています。
いいえ。組み込み関数とよく似た名前の関数を作成しないでください。ただし、実際には反対の操作です。それはあなたには直感的に思えるかもしれませんが、他の開発者にとって、そして将来あなたがより多くの経験を積んでいるあなた自身にとってさえ非常に混乱するでしょう。
max
の意味は「最大値」ですが、「直感的」な理解は「最大値」のようなものです。しかし、これは単に関数を誤って理解しただけであり、名前をmax
からmaximum
に変更しても、異なる解釈は伝わりません。言語デザイナーが間違いを犯したと強く信じていても、このようなことをしないでください。
しかし、提案されているようにcap(x, limit)
と言うように名前を変更することは、min
をラップするだけであっても、意図を明確に伝えるので問題ありません。
混乱を招くのは、関数名にCappedを使用するか、キャップを配置することの意味を理解していることです。それはリミッターであり、最大の何も必要としません。
最も低い、最も小さい、または最も早いものを求められた場合、Maxが適切な関数だと思いますか?
Minとmaxはそのままにしておきます。テストを書いて、少なくとも2回は正しく修正されるようにします。
プロジェクトでこれらの関数をあまり使用する必要がある場合は、使用する関数を明確にするためのヒントが表示されます。 <または>のように、口の広い部分が大きな値に面しています。
あなたの質問に答えるには:これがお勧めできない他の理由はありますか?グループプロジェクトではどうですか?独自の機能が必要であることは理にかなっていますが、これは問題ありません。それらがあなた自身のヘルパークラスにあり、インポートしない限り他の人から簡単に呼び出せないことを確認してください。 (Joes.Utilities。)
しかし、あなたの問題をもう一度見ると、基本的に私は代わりに考えているでしょう:
return (input >= 255) ? 255 : input;
これらの最小/最大関数に脳のロジックを適用しようとしているため、混乱しています。代わりに、英語で話します。 if
input
はgreater than or equal to 255
then
return 255
それ以外の場合はreturn
the input
。
それは:
if (input >= 255) {
255
} else {
input
}
私の意見。間違った理由でmax\min関数を使用している場合、これらの速度は無視できます。意味のあることをしてください。
私はあなたの問題を理解していますが、これをするのをためらいます。 min()とmax()が何をするのかを頭蓋骨にドリルインするほうが良いでしょう。
ほとんどのプログラマーは、min()関数とmax()関数が何を行うかを知っています。プログラムを読んでいてmax(x、y)が表示されている場合は、それが何をするのかすぐにわかります。独自の「エイリアス」関数を作成すると、コードを読んでいる他の誰もがこのエイリアスの機能を知ることはありません。彼らはあなたの機能を見つけなければなりません。それは不必要に読書の流れを壊し、読者にあなたのプログラムを理解するためにいくつかの特別な考えを強いる。
ある時点でどちらを使用するかがわからない場合は、コメントを追加して説明します。次に、将来の読者が同様に混乱する場合は、コメントでそれを明確にする必要があります。あるいは、それを誤って行ったが、コメントがあなたがやろうとしていたことを説明している場合、それをデバッグしようとしている人には手掛かりがあります。
名前があなたの直感と衝突するので関数にエイリアスを付けると...これが問題になる唯一のケースですか?または、他の関数のエイリアスを作成しますか? 「read」と混同していて、「accept」と考える方が簡単だと思うかもしれません。「append」を「StringTogether」に、「round」を「DropDecimals」などに変更します。これをとんでもない極端にしてくださいそして、あなたのプログラムは理解不能になります。
実際、数年前、私はCの句読点がすべて好きではないプログラマーと一緒に働いていました。そのため、彼は「{」の代わりに「THEN」を、「}」の代わりに「END-IF」を書けるように一連のマクロを書きました。そして、他の何十ものそのような代用。それで、あなたが彼のプログラムを読もうとしたとき、それはもはやCのようにも見えませんでした。まるでまったく新しい言語を学ぶ必要があるかのようでした。 「AND」が「&」に翻訳されたか「&&」に翻訳されたかを今は覚えていません-それがポイントです。言語と図書館を学ぶために人々が行った投資を弱体化させます。
とはいえ、標準ライブラリ関数を呼び出すだけの関数は必ずしも悪いとは言えません。関数の目的がエイリアスを作成することではなく、たまたま単一の関数である動作をカプセル化することである場合、これは適切で適切な場合があります。つまり、論理的かつ必然的にプログラムのこの時点でmaxを実行する必要がある場合は、maxを直接呼び出すだけです。しかし、今日、maxを必要とする計算を実行する必要があるが、将来、別の計算を行うように変更される可能性がある場合は、中間関数が適切です。
ラッパーは作成しません。これらのラッパーの名前はそれほど重要ではありません。
あなたがやろうとしているのは、親切なコードの難読化です。あなたは2つの目的を果たす追加の層を発明しています:
不快なものを隠すことで、コードは今、そして将来は自分自身を傷つけるだけです。あなたの快適ゾーンにとどまることで成長することはできません。 min
とmax
がどのように機能するかを学ぶ必要があります。
組み込み関数の名前を変更しても問題ありません。新しい名前を使用すると、コードが大幅に明確になり、誰もが誤解しないようになります。 (C/C++を使用している場合は、何が行われているのかわかりにくいため、#defineを使用しないでください。)関数の名前は、呼び出しコードの実行内容とその理由を説明するコメントのように機能する必要があります。 。
この問題が最小と最大で発生したのはあなただけではありませんが、すべてのドメインで機能する優れた一般的な解決策はまだ見ていません。これらの関数の命名に関する1つの問題は、2つの引数の論理的意味は異なるが、同じ意味で示されていることです。
あなたの言語がそれを許すなら、あなたは試すことができます
return calculatedDiscount.ButNoMoreThen(maxAllowedDiscount)
return CDsInStocked.ButNoMoreThen(CasesInStock)