基本的に組み込み関数の名前を変更する関数を作成することはお勧めできませんか?


40

特定のコンテキストでは、最小関数と最大関数で混乱します。

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)
}

明らかに、組み込みの使用はより高速になりますが、これは私にとっては不必要なマイクロ最適化のようです。これがお勧めできない他の理由はありますか?グループプロジェクトではどうですか?


72
最小値と最大値が読みやすさを損なう場合は、通常の「if」のために交換することを検討してください。読みやすくするために、もう少しコードを書く価値がある場合もあります。
T.サール-復活モニカ

23
1つの短い投稿で、「クリーンコーディング」の概念全体が破壊されました。敬礼します!
ユアン

21
おそらく、C ++ 11 std::clamp関数などを検討できます。
-rwong

15
おそらくより良い名前はup_to(for min)and at_least(for max)でしょうか?minimizeなぜ彼らが可換であるかを理解するには少し時間がかかるかもしれませんが、彼らは、などよりも意味を伝えていると思います。
ワーボ

59
minそしてmaxまたminimizemaximizeあなたが書きたい関数の完全に間違った名前です。デフォルトminmaxはるかに理にかなっています。あなたは実際にALMOSTが関数名を正しく取得しました。この操作は、クランプまたはキャッピングと呼ばれ、2つのキャッピング関数を作成しました。お勧めcapUpperBoundcapLowBoundます。誰にどれをするかを説明する必要はありません、それは明らかです。
スリーブマン

回答:


120

他の人がすでに述べたように、組み込み関数、標準ライブラリ、または一般的に広く使用されている関数の名前に似た名前で関数を作成しないでください。一見あまり意味がない場合でも、命名規則に慣れることは可能ですが、同じことをする他の関数を導入すると、コードの機能について推論することは不可能になります名前が入れ替わりました。

標準ライブラリで使用される名前を「オーバーロード」する代わりに、正確に意味を伝える新しい名前を使用します。あなたの場合、「最小」にはあまり興味がありません。むしろ、値に上限を設定する必要があります。数学的には、これは同じ操作ですが、意味的には完全ではありません。なぜ機能だけではないのか

int cap(int value, int limit) { return (value > limit) ? limit : value; }

それは必要なことを行い、その名前からそう伝えます。(また、実装できるcapという点でminに示すようにtimster答え)。

別の頻繁に使用される関数名は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;
}

そのような一般的に知られている関数名を使用している場合、チームに参加する新しい人(しばらくしてコードに戻ってくる未来を含む)は、混乱して自分を混乱させることをcurるのではなく、何が起こっているかをすぐに理解します彼らが知っていると思った関数名についての期待。


2
また、これは正しいアプローチで、まともなコンパイラで関数がインライン展開され、その結果マシンコードがビルトインを使用するのとまったく同じになりますgetValueNotBiggerThan(X、リミット)という名前を付けでき
ファルコ

20
@Falco「キャップ」は「値を大きくしない」のほぼ同義語だと思いますが、今日はその自転車小屋をペイントするつもりはありません。;-)
5gon12eder

1
clampは、あらゆる種類の信号処理および同様の操作(画像処理など)で広く使用されているため、これも間違いなく使用します。上限と下限が必要だとは言いませんが、一方向だけでも頻繁に見ています。
Voo

1
clampも言及するつもりだった。そして、正しく記述されていれば、無限の境界/負の無限を使用できます。たとえば、数値が255を超えないようにするには(ただし、下限はありません)、を使用しますclamp(myNumber, -Infinity, 255)
キャット

115

あなたminimize(4, 10)10を返すような関数を作成する場合、あなたの仲間のプログラマがあなたを絞め殺すかもしれないので、それはお勧めできません。

(さて、多分彼らはあなたを文字通り死ぬまで絞めませんが、真剣に...それをしないでください。)


2
また、完全に可能あなたが数年後には、このコードに仕事に戻ってきたときに、あなた自身があなたが最小化呼び出すときに、あなたの数字が間違っている理由を理解しようと、いくつかの時間を費やすだろうということです...
水田

Aww ...この答えは、以前は本当にクールな(そしてかなり高い投票を得た)コメントを持っていました。(それはまた、ユーモラスな流れを助けた答えに対する最初のコメント
でした

私はパンチカードを取得し、DO NOT(「スピンドル、折り畳み、または切断しないでください」)を取り消したいと思っています。このようなものを実装した人はカードを受け取ります。
時計じかけミューズ

26

関数のエイリアスは問題ありませんが、既存の用語の意味を変更しようとしないでください

関数のエイリアスを作成しても構いません -共通ライブラリは常にそうします

ただし、maxとminを反転させる例のように、一般的な使用法とは逆の方法で用語を使用するのは悪い考えです。他のプログラマにとっては混乱を招くので、これらの用語を非標準的な方法で解釈し続けるように自分自身を訓練することにより、自分自身を傷つけることになります。

したがって、あなたの場合、混乱を招く「最小/最大」という用語を捨てて、独自のわかりやすいコードを作成してください。

例のリファクタリング:

int apply_upper_bound(int x, int y)
{
    return min(x, y);
}


int apply_lower_bound(int x, int y)
{
    return max(x, y)
}

追加のボーナスとして、このコードを見るたびに、プログラミング言語でminmaxがどのように使用されるかを思い出します。最終的に、それはあなたの頭の中で意味をなすようになるでしょう。


4
私はあなたがOPの適用を誤解してminおり、maxそれがOPを混乱させていると思います。それはときだmin設定するために使用される固定上側の境界いくつかの値にします。get_lower_valueこのアプリケーションでも直観に反するでしょう。この操作に別の名前を選択した場合、それをsupremumと呼びますが、何人のプログラマーがすぐにそれを理解するかはわかりません。
左辺約

3
@leftaroundabout:セット{1、2}の上限は2であるため、上記で定義supremumした関数の名前を使用しget_lower_valueて単にを呼び出すことはしないでくださいmin。それは次のプログラマーにそれを呼ぶと全く同じ問題を引き起こしmaximiseます。私はそれを呼び出すことをお勧めしますがapply_upper_bound、それが完璧かどうかはわかりません。パラメーターをどのように配置しても同じように機能するため、それはまだ奇妙ですが、名前はパラメーターの1つが「値」であり、もう1つが「境界」であり、それらが何らかの形で異なることを意味します。
スティーブジェソップ

1
読者は英語の意味ではなくあなたの意味を理解できるように、基本的に最高語に精通しすぎないように読者に頼っていると思います。あなたのコードにローカルな専門用語を定義することは問題ありませんが、質問の種類のポイントは、あなたが望む専門用語がすでに馴染みのある意味と直接矛盾するとき何をするかということです、そして私はあなたがまだそれをしていると思いますSTEM科目を勉強した人にのみ関連する「英語」のバージョン)
スティーブジェソップ

3
この関数「関数のエイリアスは問題ありませんが、既存の用語の意味を変えようとしないでください」は完璧で美しく表現されています。第二に、組み込み関数に関連して混乱を招くような方法で名前を変更するべきではないという考え(および組み込み関数の名前が/愚か/混乱している場合でも)は完璧な考えです。このページで出てきたmax / minのについて、それは完全な混乱です。
ファッティ

1
OK、答えを編集して、OPの推論に適合し、用語のオーバーロードを回避する「apply_upper_bound」を使用しました。冗長性は問題ではありません。ここでは完璧なメソッド名を書くつもりはありません。エイリアスの命名に関するいくつかの基本的なルールを設定するだけです。OPは、最も明確で簡潔であると思うものに編集できます。
ティムグラント

12

この質問が大好きです。それを分解しましょう。

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);

彼らはあなたが間違いを犯したことを知っています。


6
おかしい!この例では、opが関係する正確なエラーを作成しました。休日の数をmaxHolidaysAllowed以下にしたいので、nee min(a、b)
Falco

14
クリーンなコードFunctionWhichReturnsTheLargestOfItsParametersが、のような滑dicな名前が良いことであると本当に示唆している場合、私はそれの一部を望みません。
デビッドハンメン

1
@Falco笑おっと!!!
ユアン

4
@DavidHammen:実際のプログラミングスタイルでは、FunctionWhichReturnsすべての関数の前面にイボを配置する(例外をスローしたり終了したりしない)ため、実際にはそうではありません。ただし、(a)純粋な関数および/または「getter」がいぼを使用するべきであるという線に沿って実際のアドバイスに従うことによりgetMinimumgetLarger(またはgetLargest2つ以上の入力)にgetなる可能性があります。名前。明らかに、そのような関数を呼び出すことに決めた人にとってはあまりにも冗長ですmax
スティーブジェソップ

1
はい、@ falcoのコメントを参照してください。その後、本当に修正できませんでした!
ユアン

4

いいえ。組み込み関数に非常に似た名前の関数を作成しないでください。ただし、実際には反対のことを行います。直感的には思えるかもしれませんが、他の開発者にとっては混乱を招き、将来的にはより多くの経験があれば自分自身にとっても混乱を招きます。

の意味maxは「最大」ですが、あなたの「直感的な」理解は「最大まで」のようなものです。ただし、これは単に関数の誤った理解であり、名前をからmaxに変更しmaximumても、別の解釈を伝えることはありません。言語デザイナーが間違いを犯したと強く信じていても、このようなことはしないでください。

しかし、cap(x, limit)提案されているように名前を変更することは、単にラップするだけでも意図を明確に伝えるため、問題ありませんmin


3

混乱を招く可能性があるのは、関数名にCappedを使用するか、capを配置することの意味を理解することです。これはリミッターであり、最大値を必要としません。

最も低い、最も小さい、または最も早いものを要求された場合、Maxが適切な関数であると感じますか?

minとmaxはそのままにします。少なくとも2回目に正しい結果が得られるように、テストを作成します。

プロジェクトでこれらの関数をあまり使用する必要がある場合は、使用する関数を明確にするためのヒントがいくつかあります。<や>のように、口の広い部分が大きな値に面しています。


1
根本的な問題として用語の混乱が考えられる場合は、+ 1。混乱は「合計を返す、最大 255」というコメントから始まると思うので、彼はmax関数がより適切であると考えていますが、論理的にminは彼が実際に探しているものです。
レヴナント

2

あなたの質問に答えるために:これがお勧めできない他の理由はありますか?グループプロジェクトではどうですか?独自の機能が必要なことは理にかなっていますが、これは問題ありません。それらがあなた自身のヘルパークラスにあり、インポートしない限り他の人に簡単に呼び出せないことを確認してください。(Joes.Utilities。)

しかし、あなたの問題をもう一度見ると、基本的に私は代わりに考えているでしょう:

return (input >= 255) ? 255 : input;

これらの最小/最大関数に脳のロジックを適用しようとしているため、混乱している。代わりに、ただ英語で話してください。あるそう。ifinputgreater than or equal to 255 then return 255returninput

どちらですか:

if (input >= 255) {
   255 
} else {
   input
}

私の意見。間違った理由でmax \ min関数を使用する場合、これらの速度は無視できます。意味のあることをしてください。


1
私の先輩の同僚の一人は、「コンピューターにあなたのために考えさせる」といつも言っていました。

1

私はあなたの問題を理解していますが、私はこれをしたがりません。min()とmax()が行うことを頭蓋骨に単純にドリルする方が良いでしょう。

ほとんどのプログラマーは、min()関数とmax()関数が何をするかを知っています-あなたのように、いつでも使用する直感に苦労する場合もあります。プログラムを読んでいてmax(x、y)を見ると、それが何をするのかすぐにわかります。独自の「エイリアス」関数を作成すると、コードを読んでいる他の人はこのエイリアスが何をするのかわかりません。彼らはあなたの機能を見つけなければなりません。それは不必要に読書の流れを壊し、読者にあなたのプログラムを理解するためにいくつかの余分な思考をさせます。

ある時点でどちらを使用するかわからない場合は、それを説明するコメントを追加してください。次に、将来の読者が同様に混乱している場合、あなたのコメントはそれをクリアするはずです。または、あなたがそれを間違えたが、コメントがあなたが何をしようとしていたかを説明している場合、それをデバッグしようとしている人は手がかりを得るでしょう。

名前があなたの直感と衝突するために関数をエイリアス化したら...これが問題になる唯一のケースですか?または、他の関数のエイリアスを作成しますか?「読み取り」に混乱し、「受け入れる」と考える方が簡単だと思うかもしれません。「追加」を「StringTogether」に、「ラウンド」を「DropDecimals」などに変更します。あなたのプログラムは理解できないでしょう。

実際、数年前、私はCの句読点がすべて好きではないプログラマーと仕事をしていました。そこで彼は、「{」の代わりに「THEN」、「}」の代わりに「END-IF」そして、他の数十のそのような代替。それで、あなたが彼のプログラムを読もうとしたとき、それはもはやCのようには見えず、まるでまったく新しい言語を学ばなければならないようなものでした。「AND」が「&」と「&&」のどちらに翻訳されたか覚えていません。それがポイントです。あなたは人々が言語と図書館を学ぶために行った投資を損なう。

そうは言っても、標準ライブラリ関数を呼び出す以外の何もしない関数は必ずしも悪いとは言いません。関数の目的がエイリアスを作成することではなく、たまたま単一の関数である動作をカプセル化することである場合、これは適切で適切です。つまり、論理的かつ必然的に、プログラムのこの時点でmaxを実行する必要がある場合は、maxを直接呼び出します。しかし、今日最大値を必要とする計算を実行する必要があるが、将来別の何かを行うために修正される可能性がある場合は、中間関数が適切です。


0

組み込み関数の名前を変更しても、新しい名前によってコードが明確になり、誰もが誤解することはありません。(C / C ++を使用している場合は、#defineを使用しないでください。何が起こっているのかわかりにくいためです。)関数の名前は、呼び出し元のコードが何をしていて、なぜ。

最小値と最大値でこの問題が発生したのはあなただけではありませんが、すべてのドメインで有効な一般的な解決策はまだありません。これらの関数の命名に関する1つの問題は、2つの引数が異なる論理的意味を持っているが、同じ意味として提示されていることだと思います。

言語で許可されている場合は、試してみてください

return  calculatedDiscount.ButNoMoreThen(maxAllowedDiscount)

return  CDsInStocked.ButNoMoreThen(CasesInStock)

0

いや

ラッパーは書きません。これらのラッパーの名前はそれほど重要ではありません。

あなたがやろうとしているのは、親切なコードの難読化です。次の2つの目的に役立つ追加のレイヤーを作成しています。

  1. 他の人はあなたのコードを理解できません。
  2. 他の人のコードを理解することを決して学ばない。

気に入らないものを隠すことで、現在および将来自分自身のコードを傷つけているだけです。快適なゾーンにとどまって成長することはできません。必要なのは、方法minmax作業を学ぶことです。


-1

大丈夫で、Min、Maxを使用してオーバーシュートやアンダーシュートを抑えるのは本当に直感的ではありません。これも使用して行われます:

  • floor()およびceil()
  • クランプ、制限、境界
  • そしてもちろん、高次の切り捨てを伴うmod。

ファームウェアでは、この拡張性に依存する最新の3Dグラフィックスよりも前のMMXに比べてさかのぼります。

業界標準の機能をローカルで置き換えても心配することはありませんが、派生名の方が良いかもしれません。C ++の学生は、おそらく彼らのあいまいなクラスのために過負荷になるかもしれません。


すみません、MMXとは何ですか?
トビアテサン

結果が制限されている「飽和値」を考えていました。境界とオーバーフローのテストを含める必要がない場合は、コードをよりシンプルにすることができます(負の制限を超えて移動したり、正になったりすることを避けるためにグラフィックスに)。PSUBSB / PSUBSW。メカニズムは同じではないかもしれないと思いますが、機能の効果と意図は同じです。
mckenzm

-1

これは、いくつかのケースで罰金ですが、ではない:それ単語にはるかに良い方法がありますので、あなたの例では
saturateclampclip、など


-1

「bounded」という名前の汎用関数を作成したい

//Assumes lower_bound <= upper_bound
template <typename T>
T bounded(T value, T lower_bound, T upper_bound){
    if (value < lower_bound)
        return lower_bound;
    if (value > upper_bound)
        return upper_bound;
    return value;
}

//Checks an upper (by default) or lower bound
template <typename T>
T bounded(T value, T bound, bool is_upper_bound = true){
    if (is_upper_bound){
        if (value > bound)
            return bound;
    }
    else {
        if (value < bound)
            return bound;
    }
    return value;
}

または、「min」と「max」を使用して

//Assumes lower_bound <= upper_bound
template <typename T>
T bounded(T value, T lower_bound, T upper_bound){
    return max(min(value, upper_bound), lower_bound);
}

//Checks an upper (by default) or lower bound
template <typename T>
T bounded(T value, T bound, bool is_upper_bound = true){
    if (is_upper_bound)
        return min(value, bound);
    else
        return max(value, bound);
}

-1

関数の呼び出しについてはどうですか:

atmost(x,255):xの低い方または最大で255を返します。

atleast(10,x):xの高い方または少なくとも10を返します。


-1

min(x+y, MAX_VALUE); よりもはるかに多くの意味を運ぶ myCustomFunction(x, y);

したがって、答えは「はい」です。お勧めできません。それはあなたの脳言語のエイリアスとしてのみ機能します。

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