¿Assert es malo? [cerrado]


Los creadores del lenguaje Go escriben :

Go no proporciona afirmaciones. Son innegablemente convenientes, pero nuestra experiencia ha sido que los programadores los utilizan como una muleta para evitar pensar en el manejo adecuado de errores y la presentación de informes. El manejo adecuado de errores significa que los servidores continúan operando después de errores no fatales en lugar de bloquearse. El informe de errores adecuado significa que los errores son directos y al punto, ahorrando al programador de interpretar un crash trace. Los errores precisos son particularmente importantes cuando el programador que ve los errores no está familiarizado con el código.

¿Cuál es su opinión sobre esto?

Author: Frank, 2009-12-06

21 answers

No, no hay nada malo con assert siempre y cuando lo uses como se pretende.

Es decir, se supone que es para la captura de casos que "no pueden suceder", durante la depuración, en lugar de la gestión de errores normal.

  • Assert: Un fallo en la propia lógica del programa.
  • Manejo de errores: Una entrada errónea o estado del sistema no debido a un error en el programa.
 311
Author: caf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-06 04:20:46

No, ni goto ni assert son malos. Pero ambos pueden ser mal utilizados.

Assert es para comprobaciones de cordura. Cosas que deberían matar al programa si no son correctas. No para validación o como reemplazo para el manejo de errores.

 106
Author: gahooa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-06 04:11:30

Según esa lógica, los puntos de interrupción también son malos.

Las aserciones deben usarse como ayuda para la depuración, y nada más. "Mal" es cuando intentas usarlas en lugar de manejar errores.

Las afirmaciones están ahí para ayudarle a usted, el programador, detectar y solucionar problemas que no deben existir y verificar que sus suposiciones se mantengan verdaderas.

No tienen nada que ver con el manejo de errores, pero desafortunadamente, algunos programadores abusan de ellos como tales, y luego los declaran "malvados".

 62
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-06 10:48:42

Me gusta mucho usar assert. Me resulta muy útil cuando estoy creando aplicaciones por primera vez (tal vez para un nuevo dominio). En lugar de hacer una comprobación de errores muy elegante (que consideraría una optimización prematura) codifico rápido y agrego muchas afirmaciones. Después de saber más sobre cómo funcionan las cosas, reescribo y elimino algunas de las afirmaciones y las cambio para un mejor manejo de errores.

Debido a aseveraciones, paso mucho menos tiempo codificando/depurando programas.

He también noté que las afirmaciones me ayudan a pensar en muchas cosas que podrían romper mis programas.

 39
Author: arhuaco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-06 04:16:25

Como información adicional, go proporciona una función incorporada panic. Esto se puede usar en lugar de assert. Por ejemplo,

if x < 0 {
    panic("x is less than 0");
}

panic imprimirá el seguimiento de la pila, por lo que de alguna manera tiene el propósito de assert.

 30
Author: yuku,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-17 04:53:03

Deben usarse para detectar errores en el programa. No está mal la entrada del usuario.

Si se usan correctamente, son no malos.

 29
Author: Alex Budovski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-06 04:29:01

Esto surge mucho, y creo que un problema que hace que las defensas de las afirmaciones sean confusas es que a menudo se basan en la comprobación de argumentos. Así que considere este ejemplo diferente de cuándo podría usar una aserción:

build-sorted-list-from-user-input(input)

    throw-exception-if-bad-input(input)

    ...

    //build list using algorithm that you expect to give a sorted list

    ...

    assert(is-sorted(list))

end

Usa una excepción para la entrada porque espera que a veces obtenga una entrada incorrecta. Usted afirma que la lista está ordenada para ayudarlo a encontrar un error en su algoritmo, que por definición no espera. La aserción está solo en la compilación de depuración, por lo que a pesar de el cheque es caro, no te importa hacerlo en cada invocación de la rutina.

Todavía tiene que probar unitariamente su código de producción, pero esa es una forma diferente y complementaria de asegurarse de que su código sea correcto. Las pruebas unitarias aseguran que su rutina esté a la altura de su interfaz, mientras que las aserciones son una forma más precisa de asegurarse de que su implementación esté haciendo exactamente lo que espera que haga.

 13
Author: jtolle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-12 22:16:09

Las afirmaciones no son malas, pero pueden ser fácilmente mal utilizadas. Estoy de acuerdo con la afirmación de que "las afirmaciones se utilizan a menudo como una muleta para evitar pensar en el manejo adecuado de errores y la presentación de informes". He visto esto muy a menudo.

Personalmente, me gusta usar aserciones porque documentan suposiciones que podría haber hecho mientras escribía mi código. Si estas suposiciones se rompen mientras se mantiene el código, el problema se puede detectar durante la prueba. Sin embargo, hago el punto de eliminando cada aserto de mi código al hacer una compilación de producción (es decir, usando # ifdefs). Al eliminar las afirmaciones en la construcción de producción, elimino el riesgo de que alguien las use mal como muleta.

También hay otro problema con las aserciones. Las aserciones solo se comprueban en tiempo de ejecución. Pero a menudo es el caso de que la comprobación que le gustaría realizar podría haberse realizado en tiempo de compilación. Es preferible detectar un problema en tiempo de compilación. Para programadores de C++, boost proporciona BOOST_STATIC_ASSERT que le permite hacer esto. Para los programadores de C, este artículo ( link text ) describe una técnica que se puede utilizar para realizar aserciones en tiempo de compilación.

En resumen, la regla general que sigo es: No use aserciones en una compilación de producción y, si es posible, solo use aserciones para cosas que no se pueden verificar en tiempo de compilación (es decir, se deben verificar en tiempo de ejecución).

 8
Author: figurassa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-06 16:29:10

Admito haber usado asserts sin considerar el reporte de errores adecuado. Sin embargo, eso no quita que son muy útiles cuando se usan correctamente.

Son especialmente útiles si desea seguir el principio de "Bloqueo temprano". Por ejemplo, supongamos que está implementando un mecanismo de conteo de referencia. En ciertas ubicaciones de tu código sabes que el refcount debe ser cero o uno. Y también supongamos que si el refcount es incorrecto el programa no se bloqueará inmediatamente, pero durante el siguiente ciclo de mensajes, en cuyo momento será difícil averiguar por qué las cosas salieron mal. Una afirmación habría sido útil para detectar el error más cerca de su origen.

 5
Author: StackedCrooked,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-07 16:56:31

Prefiero evitar el código que hace cosas diferentes en debug y release.

Romper el depurador con una condición y tener toda la información del archivo/línea es útil, sin embargo, también la expresión exacta y el valor exacto.

Tener una afirmación que "evaluaría la condición solo en la depuración" puede ser una optimización del rendimiento, y como tal, útil solo en el 0.0001% de los programas, donde la gente sabe lo que está haciendo. En todos los demás casos, esto es perjudicial, ya que la expresión puede cambiar el estado del programa:

assert(2 == ShroedingersCat.GetNumEars()); haría que el programa hiciera cosas diferentes en debug y release.

Hemos desarrollado un conjunto de macros assert que lanzarían una excepción, y lo harían tanto en la versión de depuración como en la versión de lanzamiento. Por ejemplo, THROW_UNLESS_EQ(a, 20); lanzaría una excepción con el mensaje what() que tiene tanto el archivo, la línea y los valores reales de a, y así sucesivamente. Solo una macro tendría el poder para esto. El depurador se puede configurar para romper en 'throw' de la excepción específica tipo.

 5
Author: Pavel Radzivilovsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-09 13:39:15

Me disgusta afirma intensamente. Sin embargo, no iría tan lejos como para decir que son malvados.

Básicamente, una afirmación hará lo mismo que una excepción no marcada, la única excepción es que la afirmación (normalmente) no debe mantenerse para el producto final.

Si construye una red de seguridad para usted mismo mientras depura y construye el sistema, ¿por qué negaría esta red de seguridad para su cliente, o su servicio de asistencia técnica, o cualquier persona que pueda usar el software que es actualmente en construcción. Utilice excepciones exclusivamente para afirmaciones y situaciones excepcionales. Al crear una jerarquía de excepciones apropiada podrán discernir muy rápidamente una de la otra. Excepto esta vez, la afirmación permanece en su lugar y puede proporcionar información valiosa en caso de falla que de otro modo se perdería.

Así que entiendo completamente a los creadores de Go al eliminar asserts por completo y forzar a los programadores a usar excepciones para manejar la situación. Hay un explicación simple para esto, excepción son solo un mejor mecanismo para el trabajo ¿por qué seguir con las afirmaciones arcaicas?

 5
Author: Newtopian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-28 17:34:49

Respuesta corta: No, creo que las afirmaciones pueden ser útiles

 3
Author: Brendan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-06 04:09:42

Recientemente he comenzado a agregar algunas afirmaciones a mi código, y así es como lo he estado haciendo:

Mentalmente divido mi código en código de límite y código interno. El código de límite es el código que maneja la entrada del usuario, lee archivos y obtiene datos de la red. En este código, solicito la entrada en un bucle que solo sale cuando la entrada es válida (en el caso de la entrada interactiva del usuario), o tiro excepciones en el caso de archivos irrecuperables / datos corruptos de red.

El código interno lo es todo else. Por ejemplo, una función que establece una variable en mi clase podría definirse como

void Class::f (int value) {
    assert (value < end);
    member = value;
}

Y una función que recibe la entrada de una red podría leerse como tal:

void Class::g (InMessage & msg) {
    int const value = msg.read_int();
    if (value >= end)
        throw InvalidServerData();
    f (value);
}

Esto me da dos capas de cheques. Cualquier cosa en la que los datos se determinen en tiempo de ejecución siempre recibe una excepción o un manejo inmediato de errores. Sin embargo, esa comprobación adicional en Class::f con la instrucción assert significa que si algún código interno llama a Class::f, todavía tengo una comprobación de cordura. Mi código interno podría no pasar un argumento válido (porque puedo haber calculado value a partir de algunas series complejas de funciones), por lo que me gusta tener la afirmación en la función de configuración para documentar que, independientemente de quién esté llamando a la función, value no debe ser mayor o igual a end.

Esto parece encajar en lo que estoy leyendo en algunos lugares, que las afirmaciones deben ser imposibles de violar en un programa que funcione bien, mientras que las excepciones deben ser para casos excepcionales y erróneos que todavía son posibles. Debido a que en teoría estoy validando todas las entradas, no debería ser posible que mi afirmación se active. Si lo es, mi programa está mal.

 3
Author: David Stone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-07 15:54:26

assert es muy útil y puede ahorrarle mucho retroceso cuando se producen errores inesperados al detener el programa a los primeros signos de problemas.

Por otro lado, es muy fácil abusar assert.

int quotient(int a, int b){
    assert(b != 0);
    return a / b;
}

La versión correcta sería algo así como:

bool quotient(int a, int b, int &result){
    if(b == 0)
        return false;

    result = a / b;
    return true;
}

So... a la larga... en el panorama general... Debo estar de acuerdo en que assert puede ser abusado. Lo hago todo el tiempo.

 1
Author: Agnel Kurian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-07 07:43:16

assert está siendo abusado por el manejo de errores porque es menos tipeo.

Así que como diseñadores de lenguaje, deberían ver que el manejo adecuado de errores se puede hacer incluso con menos tipado. Excluir assert porque su mecanismo de excepción es detallado no es la solución. Oh espera, Go tampoco tiene excepciones. Muy mal :)

 1
Author: akuhn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-11 00:42:34

Sentí ganas de patear al autor en la cabeza cuando vi eso.

Utilizo asserts todo el tiempo en el código y eventualmente los reemplazo cuando escribo más código. Los uso cuando no he escrito la lógica requerida y quiero ser alertado cuando me encuentro con el código en lugar de escribir una excepción que se eliminará a medida que el proyecto se acerca a la finalización.

Las excepciones también se mezclan con el código de producción más fácilmente, lo que no me gusta. Una afirmación es más fácil de notar que throw new Exception("Some generic msg or 'pretend i am an assert'");

 1
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-28 17:30:50

Mi problema con estas respuestas que defienden assert es que nadie especifica claramente qué lo hace diferente de un error fatal regular, y por qué una assert no puede ser un subconjunto de una excepción . Ahora, dicho esto, ¿qué pasa si la excepción nunca es atrapada? ¿Eso lo convierte en una afirmación por nomenclatura? Y, ¿por qué querrías imponer una restricción en el lenguaje de que se pueda plantear una excepción que /nothing / pueda manejar?

 1
Author: Evan Carroll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-28 17:48:10

Sí, las afirmaciones son malas.

A menudo se utilizan en lugares donde se debe usar un manejo adecuado de errores. ¡Acostúmbrate a escribir un manejo adecuado de errores de calidad de producción desde el principio!

Generalmente se interponen en el camino de escribir pruebas unitarias (a menos que escriba una afirmación personalizada que interactúe con su arnés de prueba). Esto se debe a menudo a que se utilizan donde se debe utilizar el manejo adecuado de errores.

En su mayoría se compilan fuera de versiones, lo que significa que ninguno de sus "testing" está disponible cuando se está ejecutando el código que realmente se libera; dado que en situaciones de subprocesos múltiples los peores problemas a menudo solo aparecen en el código de liberación, esto puede ser malo.

A veces son una muleta para diseños rotos; es decir, el diseño del código permite que un usuario lo llame de una manera que no debería ser llamado y la afirmación "evita" esto. Revisión del diseño!

Escribí sobre esto más en mi blog en 2005 aquí: http://www.lenholgate.com/blog/2005/09/assert-is-evil.html

 1
Author: Len Holgate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-24 05:48:39

Si las afirmaciones de las que estás hablando significan que el programa vomita y luego existe, las afirmaciones pueden ser muy malas. Esto no quiere decir que sean siempre lo incorrecto a usar, son una construcción que es muy fácilmente mal utilizada. También tienen muchas mejores alternativas. Cosas como esas son buenas candidatas para ser llamadas malvadas.

Por ejemplo, un módulo de terceros (o cualquier módulo realmente) casi nunca debería salir del programa que llama. Esto no le da al programador que llama cualquier control sobre el riesgo que el programa debe tomar en ese momento. En muchos casos, los datos son tan importantes que incluso guardar datos dañados es mejor que perderlos. Las afirmaciones pueden obligarle a perder datos.

Algunas alternativas a las afirmaciones:

  • Usando un depurador,
  • Consola/base de datos / otros registros
  • Excepciones
  • Otros tipos de manejo de errores

Algunos referencias:

Incluso las personas que abogan por assert piensan que solo deben usarse en el desarrollo y no en producción:

Esta persona dice que las aserciones deben usarse cuando el módulo tiene datos potencialmente dañados que persisten después de que se lanza una excepción: http://www.advogato.org/article/949.html . Esto es ciertamente un punto razonable, sin embargo, un módulo externo debe nunca prescribir cuán importantes son los datos dañados para el programa que llama (al salir "para" ellos). La forma correcta de manejar esto es lanzando una excepción que deje claro que el programa puede estar ahora en un estado inconsistente. Y dado que los buenos programas consisten principalmente en módulos (con un poco de código de pegamento en el ejecutable principal), las afirmaciones son casi siempre lo incorrecto.

 1
Author: B T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-28 14:03:11

No tanto mal como generalmente contraproducente. Hay una separación entre la comprobación de errores permanente y la depuración. Assert hace que la gente piense que toda la depuración debe ser permanente y causa problemas masivos de legibilidad cuando se usa mucho. El manejo permanente de errores debería ser mejor que cuando sea necesario, y ya que assert causa sus propios errores, es una práctica bastante cuestionable.

 0
Author: Charles Eli Cheese,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-07 02:33:30

Nunca uso assert (), los ejemplos usualmente muestran algo como esto:

int* ptr = new int[10];
assert(ptr);

Esto es malo, nunca hago esto, ¿qué pasa si mi juego está asignando un montón de monstruos? ¿por qué debería bloquear el juego, en su lugar debe manejar los errores con gracia, así que haga algo como:

CMonster* ptrMonsters = new CMonster[10];
if(ptrMonsters == NULL) // or u could just write if(!ptrMonsters)
{
    // we failed allocating monsters. log the error e.g. "Failed spawning 10 monsters".
}
else
{
    // initialize monsters.
}
 0
Author: Bob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-03 03:38:42