使函数本质上重命名内置函数是否不明智?


40

在某些情况下,我对最小和最大函数感到困惑。

在一种情况下,当您使用函数取两个值中的更大或更小值时,就没有问题。例如,

//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
如果min和max损害了您的可读性,请考虑将其换成常规的“ if”。有时值得多写一些代码以提高可读性。
T. Sar-恢复莫妮卡

23
在一篇短文中,您已经破坏了“干净编码”的整个概念。先生,我向您致敬!
伊万

21
也许您可以考虑使用C ++ 11 std::clamp函数或类似的东西。
rwong

15
也许更好的名字是up_to(for min)和at_least(for max)?我认为它们传达的含义要好于minimize等等,尽管可能要花一点时间才能理解为什么它们是可交换的。
Warbo

59
minmax,而且minimizemaximize对于要编写的函数来说,它们的名称完全错误。默认minmax更有意义。您实际上ALMOST的功能名称正确。此操作称为钳位或加帽,并且您编写了两个加帽功能。我建议capUpperBoundcapLowBound。很明显,我不必向任何人解释哪个做了。
slebetman

Answers:


120

正如其他人已经提到的那样:不要创建名称与内置,标准库或普遍使用的函数相似的函数,而要更改其行为。即使乍一看对您来说意义不大,也可能会习惯于命名约定,但是一旦您引入了其他功能相同但又具有相同功能的代码,就不可能推理出代码的功能他们的名字互换了。

不要“重载”标准库使用的名称,而是使用可以准确传达您的意思的新名称。在您的情况下,您对“最低”并不真正感兴趣。相反,您想限制一个值。从数学上讲,这是相同的操作,但从语义上讲,则不尽相同。那么为什么不只是一个功能

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

它会执行所需的操作,并从名称中告诉您。(您也可以cap按照timster答案min所示实施)。

另一个常用的函数名称是clamp。它使用三个参数,并将提供的值“限制”在其他两个值定义的间隔中。

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

如果您使用的是这样一个众所周知的函数名称,那么任何新加入团队的人(包括将来您会在一段时间后返回代码的人)都将迅速了解发生了什么,而不必因为破坏它们而使他们感到困惑,从而招致您的诅咒对他们认为知道的函数名称的期望。


2
您也可以将其命名为getValueNotBiggerThan(x,limit),这是正确的方法,使用像样的编译器,将内联该函数,并且生成的机器代码将与使用内置代码完全相同
Falco

20
@Falco我想说“帽子”几乎是“获得不超过”的代名词,但是我今天不打算画那个脱落的自行车。;-)
5gon12eder

1
clamp广泛用于各种信号处理和类似操作(图像处理等)中,所以这绝对也是我要使用的功能。尽管我不会说它需要上下限:我也经常只在一个方向上看到它。
Voo

1
clamp也要提。而且,如果编写正确,则仅当希望以一种方式绑定时,才可以使用无穷/负无穷大的约束。例如,为确保数字不大于255(但不限制下限),请使用clamp(myNumber, -Infinity, 255)

115

如果您在minimize(4, 10)返回10的情况下创建这样的函数,那我不建议您这样做,因为您的其他程序员可能会扼杀您。

(好吧,也许他们不会从字面上勒死您,但要认真对待……不要那样做。)


2
同样完全有可能的是,当您几年后重新使用此代码时,您自己将花费数小时来尝试弄清楚为什么您称之为
minimise的

糟糕...这个答案曾经有一个很酷的(而且很受好评)的评论。(这也是对答案的第一条评论,这有助于幽默感。)
TOOGAM

我一直想得到打孔卡并划掉DO NOT(“不要纺,折叠或残废”)。实施了类似操作的人会收到一张卡。
Clockwork-Muse

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
我想你误解的应用程序minmax其迷惑OP。当它min被用来设定一个固定的上边界上的一些价值。get_lower_value在该应用程序中将是违反直觉的。如果要为此操作选择一个替代名称,我会称其为supremum,尽管我不确定有多少程序员会立即理解这一点。
大约23年

3
@leftaroundabout:集合{1,2​​}的最高值为2,所以不要使用上面定义supremum的函数的名称get_lower_value来调用min。它导致下一个程序员与调用它完全相同的问题maximise。我建议将其命名为apply_upper_bound,但我不确定是否完美。仍然很奇怪,因为无论您使用哪种方式放置参数,它的工作方式都相同,但是名称暗示参数之一是“值”,而另一个参数是“界限”,并且它们有所不同。
史蒂夫·杰索普

1
我认为您基本上是在依赖读者对supremum这个单词不太熟悉,以便他们理解您的意思而不是英语的意思。在代码的本地定义术语是可以的,但是问题的关键是当您想要的术语与已经很熟悉的含义直接矛盾时该怎么办,而且恐怕我认为您仍在这样做(因为某些版本的“英语”仅与那些学习过STEM主题的人有关)
Steve Jessop

3
这项“别名功能很好,但不要试图改变现有术语的含义”的政策是完美而精美的。其次,不要以与内置函数相关的混乱方式来重命名(并且:即使内置函数的命名不正确/愚蠢/令人困惑),也是一个完美的想法。再看这个页面上的最大/最小示例,这很混乱。
Fattie

1
好的,我编辑了答案以使用“ apply_upper_bound”,它既符合OP的推理,又避免了术语的超载。详细程度不是问题。我不是要在此处编写完美的方法名称,而只是为命名别名设置一些基本规则。OP可以将其编辑为他认为最清晰和简洁的内容。
蒂姆·格兰特

12

我喜欢这个问题。让我们分解一下。

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:您是否应该将“最小”重命名为“最大化”

没有!!你疯了吗?!但是是的,这个问题强调了这样一个观点,即不同的人将不同的含义理解为功能和对象名称。一个人发现清楚而又传统的另一个发现却不透明且令人困惑。这就是为什么我们要发表评论。您应该改写:

// 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,所以您需要min(a,b)
Falco

14
如果干净的代码确实暗示像这样的可笑名称FunctionWhichReturnsTheLargestOfItsParameters是一件好事,那么我就不要了。
David Hammen

1
@Falco哈哈oops !!!
伊万

4
@DavidHammen:并非如此,因为没有真正的编程风格将疣FunctionWhichReturns置于每个函数的前面(不会引发异常或终止)。不过,您可以遵循以下原则,以(a)纯函数和/或“ getters”应使用疣,然后以(b)英文单词为缩写,而最终得到getMinimumgetLarger(或getLargest输入2个以上)get名称。显然,对于那些决定调用此类函数的人来说太冗长了max
史蒂夫·杰索普

1
是的,请参阅@falco的评论。在那之后我真的无法纠正它!
伊万

4

没有。不要使名称与内置函数非常相似的函数,但实际上却相反。对于您来说,这似乎很直观,但是对于其他开发人员,甚至当您有更多经验的将来,对于您自己来说,这都会非常混乱。

的意思max是“最大的”,但是您对“直觉”的理解就像是“最大的”。但是,这是函数的只是一个错误的认识,并更改名称maxmaximum不沟通你不同的解释。即使您坚信语言设计师犯了一个错误,也不要做这样的事情。

但是将名称更改cap(x, limit)为建议的名称就可以了,因为即使它只是换行,它也确实传达了意图min


3

可能使您感到困惑的是在函数名称中使用了上限,或者您对上限的含义有所了解。它是一个限制器,不需要任何东西最多。

如果要求您提供最低,最小或最早的功能,您是否觉得Max是合适的功能?

保留最小和最大。编写测试,以便至少让您第二次正确。

如果您需要在项目中大量使用这些功能,则将提供一些提示,以帮助您明确使用哪个功能。有点像<或>,嘴巴的较大部分面对较大的值。


1
对于潜在的术语混淆,+ 1是一个潜在的问题。我认为混淆始于注释“返回总和,最大为255”,因此他认为该max功能更合适,但逻辑上min是他真正要寻找的东西。
Revenant

2

回答您的问题:还有其他不明智的理由吗?在小组项目中呢?您想要自己的功能很有意义,这没问题。只需确保它们在您自己的帮助器类中,并且除非他人导入,否则其他人不容易调用它们。(Joes.Utilities。)

但是要再次查看您的问题,基本上我会在想:

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

您会感到困惑,因为您试图将大脑逻辑应用于这些最小/最大函数。而是只说英语。ifinputgreater than or equal to 255 then return 255,否则returninput

这是:

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。但是,如果您必须执行一些今天需要最大的计算,但是将来可能会修改以执行其他操作,则可以使用中间函数。


0

重命名内置函数是可以的,只要新名称使您的代码清晰明了,任何人都不会错过。(如果使用的是C / C ++,请不要使用#define,因为这样会使很难看到正在发生的事情。)函数的名称应像注释一样,解释调用代码在做什么以及为什么这样做。 。

您不是唯一遇到最小和最大问题的人,但是我还没有看到一种适用于所有领域的通用解决方案。我认为这些函数的命名存在一个问题,即这两个参数具有不同的逻辑含义,但被表示为相同的含义。

如果您的语言允许,您可以尝试

return  calculatedDiscount.ButNoMoreThen(maxAllowedDiscount)

return  CDsInStocked.ButNoMoreThen(CasesInStock)

0

没有。

您不写包装纸。这些包装的名称不是很重要。

您正在尝试做的是一种代码混淆。您正在发明一个具有两个目的的额外层:

  1. 其他人无法理解您的代码。
  2. 您永远不会学会理解别人的代码。

通过隐藏您不满意的内容,您现在只会伤害您的代码,将来也会伤害您自己。不能停留在舒适区来成长。你需要的是学习如何minmax工作。


-1

可以,使用Min,Max来控制过冲和欠冲并不是真的违反直觉。也可以使用以下命令完成此操作:

  • floor()和ceil()
  • 钳位,限制,界限
  • 当然还有具有高阶截断的mod。

在固件中,它的历史要比MMX早,后者本身早于依靠这种扩展功能的现代3D图形。

即使在本地替换行业标准功能也会让我担心,派生名称可能会更好。C ++学生可能会因为他们晦涩的课而超负荷工作。


抱歉,MMX是什么?
Tobia Tesan

我当时在考虑“饱和值”,即结果限制在一个上限。如果不必包含边界测试和溢出测试(在图形中避免循环或超过负数限制而变为正数),则代码的想法可能会更简单。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;
}

或使用“最小”和“最大”

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

因此答案是肯定的,这是不明智的。它仅用作您的大脑语言的别名。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.