¿Es desaconsejable hacer una función que esencialmente cambie el nombre de una función incorporada?

40

Me confundo sobre las funciones mínimas y máximas, en ciertos contextos.

En un contexto, cuando usa las funciones para tomar el mayor o menor de dos valores, no hay problema. Por ejemplo,

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

Fácil. Pero en otro contexto, me confundo. Si estoy tratando de establecer un máximo o un mínimo, lo obtengo al revés.

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

¿Es desaconsejable hacer mis propias funciones de la siguiente manera?

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

Obviamente, usar los builtins será más rápido, pero esto me parece una microoptimización innecesaria. ¿Hay alguna otra razón por la que esto sería desaconsejable? ¿Qué pasa en un proyecto grupal?

Devsman
fuente
72
Si min y max están perjudicando su legibilidad, considere cambiarlos por "if" s regulares. A veces vale la pena escribir un poco más de código para tener una mejor legibilidad.
T. Sar - Restablece a Monica el
23
con una breve publicación ha destruido todo el concepto de "codificación limpia". ¡Lo saludo señor!
Ewan
21
Tal vez se puede considerar el 11 C ++ std::clampfunción o algo similar.
rwong
15
¿Quizás mejores nombres serían up_to(para min) y at_least(para max)? Creo que transmiten el significado mejor que minimize, etc. aunque puede tomar un momento pensar en por qué son conmutativos.
Warbo
59
miny maxy también minimizey maximizeson nombres totalmente incorrectos para las funciones que desea escribir. El valor predeterminado miny maxtiene mucho más sentido. En realidad, casi tienes los nombres de las funciones correctas. Esta operación se llama sujeción o limitación y ha escrito dos funciones de limitación. Sugeriría capUpperBoundy capLowBound. No tengo que explicarle a nadie cuál hace cuál, es obvio.
slebetman

Respuestas:

120

Como otros ya han mencionado: no cree una función con un nombre que sea similar al de una función incorporada, de biblioteca estándar o de uso general, sino que cambie su comportamiento. Es posible acostumbrarse a una convención de nomenclatura incluso si no tiene mucho sentido para usted a primera vista, pero será imposible razonar sobre el funcionamiento de su código una vez que introduzca esas otras funciones que hacen lo mismo pero tienen sus nombres intercambiados.

En lugar de "sobrecargar" los nombres utilizados por la biblioteca estándar, use nombres nuevos que transmitan exactamente lo que quiere decir. En su caso, no está realmente interesado en un "mínimo". Por el contrario, desea limitar un valor. Matemáticamente, esta es la misma operación pero semánticamente, no lo es del todo. Entonces, ¿por qué no solo una función?

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

eso hace lo que se necesita y lo dice por su nombre. (También puede implementar capen términos de mincomo se muestra en la respuesta de timster ).

Otro nombre de función de uso frecuente es clamp. Toma tres argumentos y "sujeta" un valor proporcionado en el intervalo definido por los otros dos valores.

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

Si está utilizando un nombre de función tan conocido, cualquier persona nueva que se una a su equipo (incluido el futuro en el que regrese al código después de un tiempo) comprenderá rápidamente lo que está sucediendo en lugar de maldecirlo por haberlos confundido al romper su expectativas sobre los nombres de funciones que creían saber.

5gon12eder
fuente
2
También podría nombrarlo getValueNotBiggerThan (x, limit), este es el enfoque correcto, y con un compilador decente, la función estará en línea y el código de máquina resultante será exactamente el mismo que el uso de las funciones integradas
Falco
20
@Falco Yo diría que "gorra" es casi un sinónimo de "obtener un valor no mayor que" pero no voy a pintar ese cobertizo para bicicletas hoy. ;-)
5gon12eder
1
clampse usa ampliamente en todo tipo de procesamiento de señales y operaciones similares (procesamiento de imágenes, etc.), por lo que definitivamente eso es lo que también usaría. Aunque no diría que requiere límites superiores e inferiores: también lo he visto con bastante frecuencia en una sola dirección.
Voo
1
clampTambién iba a mencionarlo . Y si está escrito correctamente, puede usar un límite de infinito / infinito negativo para cuando solo lo desee de una manera. Por ejemplo, para asegurarse de que un número no sea mayor que 255 (pero sin límite inferior), usaría clamp(myNumber, -Infinity, 255).
Kat
115

Si realiza una función como esa donde minimize(4, 10)devuelve 10 , entonces diría que no es aconsejable porque sus programadores pueden estrangularlo.

(Bueno, tal vez no te estrangularán literalmente hasta la muerte, pero en serio ... No hagas eso).

Telastyn
fuente
2
También es muy posible que cuando regrese a trabajar en este código en unos años, usted mismo pasará varias horas tratando de descubrir por qué sus cifras están equivocadas cuando llama a minimizar ...
Paddy
Aww ... esta respuesta solía tener un comentario realmente genial (y muy votado). (También fue el primer comentario sobre la respuesta, que ayudó al flujo humorístico.)
TOOGAM
Sigo queriendo obtener tarjetas perforadas y tachar el DO NOT(fuera de "NO girar, doblar o mutilar"). Alguien que implementara algo como esto recibiría una tarjeta.
Clockwork-Muse
26

Aliasing una función está bien, pero no intente cambiar el significado de los términos existentes

Está bien crear un alias de la función: las bibliotecas comunes lo hacen todo el tiempo .

Sin embargo, es una mala idea usar términos de una manera contraria al uso común, como su ejemplo en el que, en su opinión, deberían invertirse max y min. Es confuso para otros programadores, y se hará un mal servicio al entrenarse para seguir interpretando estos términos de una manera no estándar.

Entonces, en su caso, abandone el lenguaje "mínimo / máximo" que le parezca confuso y cree su propio código fácil de entender.

Refactorizando tu ejemplo:

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


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

Como una ventaja adicional, cada vez que vea este código, se recordará cómo se usan min y max en su lenguaje de programación. Eventualmente, tendrá sentido en tu cabeza.

Tim Grant
fuente
44
Creo que ha entendido mal la aplicación de miny maxque confunde el OP. Es cuando minse usa para establecer un límite superior fijo en algún valor. get_lower_valuesería tan contraintuitivo en esta aplicación. Si tuviera que elegir un nombre alternativo para esta operación, lo llamaría supremum , aunque no estoy seguro de cuántos programadores lo entenderían de inmediato.
Leftaroundabout
3
@leftaroundabout: el supremum del conjunto {1, 2} es 2, así que no use el nombre supremumde la función get_lower_valueque se definió anteriormente solo para llamar min. Causa al siguiente programador exactamente el mismo problema que llamarlo maximise. Sugeriría llamarlo apply_upper_bound, pero no estoy seguro de que sea perfecto. Todavía es extraño porque funciona de la misma manera en que coloca los parámetros, pero el nombre implica que uno de los parámetros es "el valor" y el otro es "el límite", y que de alguna manera son diferentes.
Steve Jessop
1
Creo que básicamente confías en que el lector no esté demasiado familiarizado con la palabra supremum, para que tomen tu significado en lugar del inglés. Está bien definir la jerga local a su código, pero el punto de la pregunta es qué hacer cuando la jerga que desea contradice directamente un significado ya familiar, y me temo que creo que todavía lo está haciendo (por alguna versión de "inglés" relevante solo para aquellos que han estudiado materias STEM)
Steve Jessop
3
Esta política "Aliasing una función está bien, pero no intente cambiar el significado de los términos existentes" es perfecta y bellamente expresada. En segundo lugar, la idea de que no debe cambiar el nombre de una manera confusa en relación con las funciones integradas (e: incluso si las funciones integradas tienen un nombre pobre / estúpido / confuso) es una idea perfecta. En cuanto al ejemplo de max / min que apareció en esta página, es una confusión total, je.
Fattie
1
OK, edité la respuesta para usar "apply_upper_bound", que se ajusta al razonamiento del OP y evita la sobrecarga de terminología. La verbosidad no es un problema. No me propongo escribir el nombre del método perfecto aquí, solo establezco algunas reglas básicas para nombrar alias. El OP puede editarlo a lo que encuentre más claro y conciso.
Tim Grant
12

Me encanta esta pregunta Vamos a desglosarlo sin embargo.

1: ¿Debería ajustar una sola línea de código?

Sí, puedo pensar en muchos ejemplos en los que podrías hacer esto. Quizás esté aplicando parámetros escritos u ocultando una implementación concreta detrás de una interfaz. En su ejemplo, esencialmente está ocultando una llamada a un método estático.

Además, puedes hacer muchas cosas en una sola línea en estos días.

2: ¿Son confusos los nombres 'Min' y 'Max'?

¡Sí! ¡Están totalmente! Un gurú de codificación limpio los renombraría "FunctionWhichReturnsTheLargestOfItsParameters" o algo así. Afortunadamente, tenemos documentación y (si tiene suerte) IntelliSense y comentarios para ayudarnos a que cualquiera que esté confundido por los nombres pueda leer lo que se supone que deben hacer.

3: ¿Deberías cambiarles el nombre a algo más tú mismo?

Sí, adelante. Por ejemplo, podrías tener:

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

Agrega significado, y la persona que llama no tiene que o quiere saber cómo calcular el valor.

4: ¿Debería cambiar el nombre de "min" para "maximizar"

¡¡No!! ¡¿estas loco?! Pero sí, la pregunta subraya el punto de que diferentes personas leen diferentes significados en nombres de funciones y objetos. Lo que una persona encuentra clara y convencional, otra lo encuentra opaco y confuso. Por eso tenemos comentarios. En su lugar, deberías escribir:

// Add x and y, but don't let it go over 255
s = min(x + y, 255);

Entonces cuando alguien lee

// Add x and y, but don't let it go over 255
s = max(x + y, 255);

Ellos saben que cometiste un error.

Ewan
fuente
66
¡Gracioso! En su ejemplo, ha cometido el error exacto al que se refiere el operador: desea que el número de días festivos no sea mayor que maxHolidaysAllowed, por lo que necesita min (a, b)
Falco
14
Si el código limpio realmente sugiere que los nombres absurdos como FunctionWhichReturnsTheLargestOfItsParametersson algo bueno, no quiero formar parte de él.
David Hammen
1
@Falco lol oops !!!
Ewan
44
@DavidHammen: en realidad no lo hace, ya que ningún estilo de programación real pone la verruga FunctionWhichReturnsal frente de cada función (que no arroja una excepción o termina). Usted podría terminar con getMinimum, getLarger(o getLargestcon más de 2 entradas), sin embargo, siguiendo el consejo real, a lo largo de las líneas que (a) funciones puras y / o "captadores" deben utilizar la verruga get, las palabras (b) en inglés no se deben abreviar en nombres Claramente, eso es demasiado detallado para aquellos que deciden llamar a tales funciones max.
Steve Jessop
1
sí, mira el comentario de @ falco. ¡Realmente no pude corregirlo después de eso!
Ewan
4

No se . No haga funciones con nombres muy similares a las funciones integradas, pero que en realidad hacen lo contrario . Puede parecer intuitivo para usted, pero será muy confuso para otros desarrolladores, e incluso para usted mismo en el futuro cuando tenga más experiencia.

El significado de maxes "el máximo de", pero su comprensión "intuitiva" es algo así como "al máximo de". Pero esto es simplemente una comprensión errónea de la función, y cambiar el nombre de maxa maximumno comunica su interpretación diferente. Incluso si cree firmemente que los diseñadores de idiomas cometieron un error, no haga algo como esto.

Pero cambiar el nombre para decir lo cap(x, limit)que se ha sugerido estaría bien, ya que claramente comunica la intención, incluso si simplemente se envuelve min.

JacquesB
fuente
3

Lo que puede confundirte es usar Capped en el nombre de tu función o tu comprensión de lo que significa colocar una tapa. Es un limitador y no requiere un máximo de nada.

Si le piden el más bajo, el más pequeño o el más temprano, ¿cree que Max es la función adecuada?

Deje min y max solo. Escriba pruebas para que al menos lo haga correctamente la segunda vez.

Si tiene que usar estas funciones tanto en su proyecto, encontrará algún tipo de sugerencia para ayudarlo a aclarar cuál usar. Algo así como <o>, la parte ancha de la boca se enfrenta al valor más grande.

JeffO
fuente
1
+1 para la posible confusión terminológica como un problema subyacente. Creo que la confusión comienza con el comentario "devolver la suma, con el máximo de 255", por lo que piensa que la maxfunción es más apropiada, pero lo lógico mines lo que realmente está buscando.
Revenant
2

Para responder a su pregunta: ¿Hay alguna otra razón por la que esto no sería aconsejable? ¿Qué pasa en un proyecto grupal? Tiene sentido que desee sus propias funciones, lo cual no es un problema. Solo asegúrate de que estén en tu propia clase auxiliar y que no puedan llamarse fácilmente para otros a menos que lo importen. (Joes.Utilities.)

Pero para ver nuevamente su problema, básicamente estaría pensando:

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

Te estás confundiendo porque estás tratando de aplicar la lógica de tu cerebro a estas funciones mín. / Máx. En cambio, solo habla en inglés. ifel inputes de lo greater than or equal to 255 then return 255contrario returnel input.

Cual es:

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

Mi opinión. Vas por las funciones max \ min por razones equivocadas, la velocidad de estas cosas es insignificante. Haz lo que tenga sentido.

Digno7
fuente
1
Uno de mis colegas mayores siempre solía decir "Deja que la computadora piense por ti".
1

Si bien entiendo tu problema, sería reacio a hacer esto. Sería mejor simplemente perforar en el cráneo lo que hacen min () y max ().

La mayoría de los programadores saben lo que hacen las funciones min () y max (), incluso si, como usted, a veces luchan con su intuición sobre qué usar en un momento dado. Si estoy leyendo un programa y veo max (x, y), inmediatamente sé lo que hace. Si crea su propia función de "alias", cualquiera que lea su código no sabrá qué hace este alias. Tienen que encontrar tu función. Rompe innecesariamente el flujo de lectura y obliga al lector a pensar un poco más para comprender su programa.

Si tiene problemas para determinar cuál usar en algún momento, diría que agregue un comentario que lo explique. Entonces, si un futuro lector está igualmente confundido, su comentario debería aclararlo. O si lo hace mal, pero el comentario explica lo que estaba tratando de hacer, la persona que intenta depurarlo tendrá una pista.

Una vez que alias una función porque el nombre choca con tu intuición ... ¿es este el único caso en el que eso es un problema? ¿O vas a alias otras funciones? Tal vez estás confundido por "leer" y te resulta más fácil pensar que es "aceptar", cambias "agregar" a "StringTogether", "round" a "DropDecimals", etc., etc. Lleva esto a un extremo ridículo y tus programas serán incomprensibles.

De hecho, hace años trabajé con un programador al que no le gustaban todos los signos de puntuación en C. Así que escribió un montón de macros para dejarle escribir "ENTONCES" en lugar de "{" y "END-IF" en lugar de "}" y docenas de otras sustituciones similares. Entonces, cuando trataste de leer sus programas, ya ni siquiera parecía C, fue como tener que aprender un lenguaje completamente nuevo. Ahora no recuerdo si "Y" se tradujo a "&" o "&&", y ese es el punto. Socava la inversión que la gente ha hecho para aprender el idioma y la biblioteca.

Dicho esto, no diría que una función que no hace nada más que llamar a una función de biblioteca estándar es necesariamente mala. Si el objetivo de su función no es crear un alias, sino encapsular el comportamiento que resulta ser una sola función, esto podría ser bueno y apropiado. Quiero decir, si lógicamente e inevitablemente tienes que hacer un máximo en este punto del programa, simplemente llama a max directamente. Pero si tiene que realizar algún cálculo que hoy requiere un máximo, pero que podría modificarse en el futuro para hacer otra cosa, entonces es apropiada una función intermedia.

Arrendajo
fuente
0

Está bien cambiar el nombre de las funciones integradas, siempre que los nuevos nombres aclaren mucho su código y nadie lo extrañe. (Si está utilizando C / C ++, no use un #define ya que dificulta ver lo que está sucediendo). El nombre de una función debe actuar como un comentario que explique qué está haciendo el código de llamada y por qué lo está haciendo. .

No eres la única persona que ha tenido este problema con min y max, sin embargo, todavía no he visto una buena solución general que funcione en todos los dominios. Creo que un problema con el nombramiento de estas funciones es que los dos argumentos tienen significados lógicos diferentes, pero se presentan con el mismo significado.

Si su idioma lo permite, puede intentar

return  calculatedDiscount.ButNoMoreThen(maxAllowedDiscount)

return  CDsInStocked.ButNoMoreThen(CasesInStock)
Ian
fuente
0

No.

No escribes tus envoltorios. Los nombres de esos envoltorios no son muy significativos.

Lo que intenta hacer es una ofuscación de código amable. Estás inventando una capa adicional que tiene 2 propósitos:

  1. Otras personas no pueden entender tu código.
  2. Nunca aprendes a entender el código de otras personas.

Al ocultar cosas con las que no te sientes cómodo, solo estás dañando tu código ahora y a ti mismo en el futuro. No puedes crecer si te quedas en tu zona de confort. Lo que necesitas es aprender cómo miny maxtrabajar.

Agent_L
fuente
-1

Está bien, y no es realmente contradictorio usar Min, Max para controlar y sublimar. Esto también se hace usando:

  • piso () y techo ()
  • abrazadera, límite, límites
  • y, por supuesto, mod con truncamiento de alto orden.

En el firmware se remonta más allá de MMX, que es anterior a los gráficos 3D modernos que se basan en este extenso.

Reemplazar una función estándar de la industria incluso localmente me preocuparía, un nombre derivado puede ser mejor. Los estudiantes de C ++ podrían sobrecargarse para su clase oscura quizás.

mckenzm
fuente
Lo siento, ¿qué pasa con MMX?
Tobia Tesan
Estaba pensando en "valores saturados", donde el resultado está limitado a un límite. La idea era que el código podría ser más simple si no tuviera que incluir pruebas de límite y desbordamiento (en gráficos para evitar los ciclos o ser positivo al viajar más allá de los límites negativos). PSUBSB / PSUBSW. Admito que el mecanismo puede no ser el mismo, pero el efecto y la intención de la función sí lo son.
mckenzm
-1

Está bien, en algunos casos, pero no en su ejemplo, porque hay maneras mucho mejores a la palabra que:
saturate, clamp, clip, etc.

Mehrdad
fuente
-1

Prefiero crear una función genérica llamada 'acotada'

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

o con el uso de 'min' y '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);
}
David Ferrer
fuente
-1

¿Qué hay de llamar a sus funciones:

atmost(x,255): devuelve la menor de x o 255 como máximo.

atleast(10,x): devuelve la mayor de x o al menos 10.

Espadaña
fuente
-1

min(x+y, MAX_VALUE); tendría mucho más significado que myCustomFunction(x, y);

Entonces la respuesta es SÍ, no es aconsejable . Sirve solo como un alias para su lenguaje cerebral.

Chispa
fuente