¿No es aconsejable realizar una función que esencialmente cambie el nombre de una función incorporada?

40

Me confundo con las funciones mín y máx, en ciertos contextos.

En un contexto, cuando estás usando las funciones para tomar el mayor o el 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 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
}

¿No es aconsejable realizar 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, el uso de los componentes integrados será más rápido, pero para mí esto parece una microoptimización innecesaria. ¿Hay alguna otra razón por la que esto sería desaconsejable? ¿Qué hay en un proyecto grupal?

    
pregunta Devsman 08.06.2016 - 20:35

15 respuestas

120

Como ya han mencionado otros: 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 aunque no tenga 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 que tienen sus nombres intercambiados.

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

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

que hace lo que se necesita y lo dice a partir de su nombre. (También puede implementar cap en términos de min como se muestra en timster 's answer ).

Otro nombre de función usado frecuentemente es clamp . Toma tres argumentos y "sujeta" un valor proporcionado al 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á usando un nombre de función tan conocido en general, cualquier persona nueva que se una a su equipo (incluido el futuro, volverá al código después de un tiempo) entenderá rápidamente lo que está sucediendo en lugar de maldecirlo por haberlo confundido. al romper sus expectativas sobre los nombres de funciones que creían conocer.

    
respondido por el 5gon12eder 08.06.2016 - 22:16
115

Si realizas una función como esa donde minimize(4, 10) devuelve 10 , entonces diría que no es aconsejable porque tus compañeros programadores pueden estrangularte.

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

    
respondido por el Telastyn 08.06.2016 - 20:42
26

El alias de una función está bien, pero no intentes cambiar el significado de los términos existentes

Está bien crear un alias de la función - bibliotecas comunes hazlo 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, debe invertirse max y min. Es confuso para otros programadores, y usted se estará perjudicando al entrenarse para seguir interpretando estos términos de una manera no estándar.

Entonces, en tu caso, abandona el lenguaje "mínimo / máximo" que te parece confuso y crea tu 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 bono adicional, cada vez que mire este código, se recordará cómo se utilizan min y max en su lenguaje de programación. Eventualmente, llegará a tener sentido en tu cabeza.

    
respondido por el Tim Grant 08.06.2016 - 21:46
12

Me encanta esta pregunta. Vamos a descomponerlo sin embargo.

1: ¿Debes 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 de 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í! ¡Ellos son totalmente! Un gurú de codificación limpio les cambiaría el nombre por "FunctionWhichReturnsTheLargestOfItsParameters" o algo así. Afortunadamente, tenemos documentación y (si tiene suerte) IntelliSense y comentarios para ayudarnos, así que cualquier persona que esté confundida por los nombres pueden leer lo que se supone que deben hacer.

3: ¿Deberías cambiarles el nombre a otra persona?

Sí, ve por ello. Por ejemplo, podría 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 querer o saber cómo calcular el valor.

4: Si cambia el nombre de "min" a "maximizar"

¡¡No !! ¿estás 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 claro y convencional, otra opaco y confuso. Es por eso que 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);

Luego, cuando alguien lee

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

saben que cometiste un error.

    
respondido por el Ewan 08.06.2016 - 22:02
4

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

El significado de max es "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 max a maximum no 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 que diga cap(x, limit) como se ha sugerido estaría bien, ya que claramente comunica la intención, incluso si simplemente ajusta min .

    
respondido por el JacquesB 09.06.2016 - 16:59
3

Lo que puede confundirlo es usar Capped en el nombre de su función o su comprensión de lo que significa colocar un límite. Es un limitador y no requiere un máximo de nada.

Si se te pide el más bajo, el más pequeño o el más antiguo, ¿sientes que Max es la función adecuada?

Deja min y max solo. Escribe pruebas para que al menos lo hagas correctamente la segunda vez.

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

    
respondido por el JeffO 08.06.2016 - 21:19
2

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

Pero para volver a analizar su problema, básicamente pensaría:

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

Te estás confundiendo porque estás tratando de aplicar tu lógica cerebral a estas funciones mín / máx. En su lugar solo habla en ingles. if el input es greater than or equal to 255 then return 255 de lo contrario return el input .

Que es:

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

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

    
respondido por el Worthy7 09.06.2016 - 07:26
1

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

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

Si tiene problemas para averiguar cuál usar en algún momento, le diría, agregue un comentario que lo explique. Luego, si un futuro lector está igualmente confundido, su comentario debería aclararlo. O si lo haces mal, pero el comentario explica lo que estabas tratando de hacer, la persona que lo intente tendrá una pista.

Una vez que creas un alias en 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é confundido por "leer" y le resulte más fácil pensar que es "aceptar", cambiar "añadir" a "StringTogether", "redondear" a "DropDecimals", etc., etc. Llevar 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 gustó toda la puntuación en C. Así que escribió un montón de macros para dejarlo escribir "ENTONCES" en lugar de "{" y "FIN-IF" en lugar de "}" y docenas de otras sustituciones similares. Entonces, cuando intentaste leer sus programas, ya ni siquiera se parecía a C, era como tener que aprender un nuevo idioma. Ahora no recuerdo si "AND" se tradujo a "&" o "& &" - Y ese es el punto. Usted 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 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 al máximo 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 una función intermedia es apropiada.

    
respondido por el Jay 12.06.2016 - 08:07
0

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

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 la denominación de estas funciones es que los dos argumentos tienen significados lógicos diferentes, pero se presentan con el mismo significado.

Si tu idioma lo permite, puedes intentarlo

return  calculatedDiscount.ButNoMoreThen(maxAllowedDiscount)

return  CDsInStocked.ButNoMoreThen(CasesInStock)
    
respondido por el Ian 09.06.2016 - 11:00
0

No.

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

Lo que estás tratando de hacer es una ofuscación de código amable. Estás inventando una capa adicional que cumple 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 se siente cómodo, solo está dañando su código ahora y a usted mismo en el futuro. No puedes crecer quedándote en tu zona de confort. Lo que necesitas es aprender cómo funcionan min y max .

    
respondido por el Agent_L 10.06.2016 - 14:09
-1

Está bien, y no es realmente contrario a la intuición utilizar Min, Max para reiniciar el proceso. Esto también se hace usando:

  • piso () y ceil ()
  • 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 a su vez es anterior a los gráficos 3D modernos que se basan en esta extensión.

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

    
respondido por el mckenzm 09.06.2016 - 04:04
-1

Está bien en algunos casos, pero no en su ejemplo, porque hay maneras mucho mejores de redactarlo:
saturate , clamp , clip , etc.

    
respondido por el Mehrdad 09.06.2016 - 05:39
-1

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

//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);
}
    
respondido por el David Ferrer 09.06.2016 - 14:58
-1

¿Qué hay de llamar a sus funciones:

atmost(x,255) : devuelve el valor más bajo de x o 255 como máximo.

atleast(10,x) : devuelve el valor más alto de x o al menos 10.

    
respondido por el Bulrush 10.06.2016 - 13:10
-1

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

Entonces la respuesta es SÍ, no es aconsejable . Solo sirve como un alias para el lenguaje de tu cerebro.

    
respondido por el SparK 09.06.2016 - 03:23

Lea otras preguntas en las etiquetas