spanish sentiment ner language example en_core_web_sm language-agnostic exception

language agnostic - sentiment - ¿Qué, y por qué, prefieres las Excepciones o los códigos de devolución?



spacy ner spanish (23)

Para algunos idiomas (es decir, C ++) la fuga de recursos no debe ser un motivo

C ++ se basa en RAII.

Si tiene un código que puede fallar, devolver o arrojar (es decir, el código más normal), debe tener su puntero dentro de un puntero inteligente (suponiendo que tenga una muy buena razón para no crear su objeto en la pila).

Los códigos de retorno son más detallados

Son detallados, y tienden a convertirse en algo así como:

if(doSomething()) { if(doSomethingElse()) { if(doSomethingElseAgain()) { // etc. } else { // react to failure of doSomethingElseAgain } } else { // react to failure of doSomethingElse } } else { // react to failure of doSomething }

Al final, tu código es una colección de instrucciones ideadas (vi este tipo de código en el código de producción).

Este código bien podría traducirse a:

try { doSomething() ; doSomethingElse() ; doSomethingElseAgain() ; } catch(const SomethingException & e) { // react to failure of doSomething } catch(const SomethingElseException & e) { // react to failure of doSomethingElse } catch(const SomethingElseAgainException & e) { // react to failure of doSomethingElseAgain }

Que limpia separadamente el código y el procesamiento de errores, lo que puede ser algo bueno .

Los códigos de retorno son más quebradizos

Si no es una advertencia oscura de un compilador (ver el comentario de "phjr"), pueden ignorarse fácilmente.

Con los ejemplos anteriores, suponga que alguien olvida manejar su posible error (esto sucede ...). El error se ignora cuando se "devuelve", y posiblemente explotará más tarde (es decir, un puntero NULL). El mismo problema no ocurrirá con excepción.

El error no será ignorado. A veces, aunque no quieras que explote ... Debes elegir cuidadosamente.

Los códigos de retorno a veces se deben traducir

Digamos que tenemos las siguientes funciones:

  • doSomething, que puede devolver un int llamado NOT_FOUND_ERROR
  • doSomethingElse, que puede devolver un bool "falso" (por error)
  • doSomethingElseSagain, que puede devolver un objeto Error (con el __LINE__, __FILE__ y la mitad de las variables de la pila.
  • doTryToDoSomethingWithAll ThisMess que, bueno ... Usa las funciones anteriores y devuelve un código de error de tipo ...

¿Cuál es el tipo de retorno de doTryToDoSomethingWithAll ThisMess si falla una de sus funciones?

Los códigos de retorno no son una solución universal

Los operadores no pueden devolver un código de error. Los constructores de C ++ tampoco pueden.

Códigos de retorno significa que no puede encadenar expresiones

El corolario del punto anterior. ¿Qué sucede si quiero escribir?

CMyType o = add(a, multiply(b, c)) ;

No puedo, porque el valor de retorno ya se usa (y, a veces, no se puede cambiar). Entonces el valor de retorno se convierte en el primer parámetro, enviado como referencia ... O no.

La excepción se escribe

Puede enviar diferentes clases para cada tipo de excepción. Las excepciones de recursos (es decir, memoria insuficiente) deben ser ligeras, pero cualquier otra cosa podría ser tan pesada como sea necesario (me gusta la excepción de Java que me da la pila completa).

Cada captura puede ser especializada.

Nunca use la captura (...) sin volver a tirar

Por lo general, no debe ocultar un error. Si no vuelve a tirar, como mínimo, registre el error en un archivo, abra un cuadro de mensaje, lo que sea ...

La excepción es ... NUKE

El problema con la excepción es que el uso excesivo de ellos producirá un código lleno de intentos / capturas. Pero el problema está en otra parte: ¿quién intenta capturar su código usando el contenedor STL? Aún así, esos contenedores pueden enviar una excepción.

Por supuesto, en C ++, nunca dejes que una excepción salga de un destructor.

La excepción es ... sincrónica

Asegúrate de atraparlos antes de que pongan tu hilo de rodillas o se propaguen dentro del ciclo de mensajes de Windows.

La solución podría ser mezclarlos?

Así que supongo que la solución es tirar cuando algo no debería suceder. Y cuando algo puede suceder, use un código de retorno o un parámetro para permitir que el usuario reaccione.

Entonces, la única pregunta es "¿qué es algo que no debería suceder?"

Depende del contrato de tu función. Si la función acepta un puntero, pero especifica que el puntero debe ser no NULL, entonces está bien lanzar una excepción cuando el usuario envía un puntero NULL (la pregunta es, en C ++, cuando el autor de la función no usó referencias en su lugar) de punteros, pero ...)

Otra solución sería mostrar el error

Algunas veces, tu problema es que no quieres errores. El uso de excepciones o códigos de retorno de error es bueno, pero ... Desea saberlo.

En mi trabajo, usamos una especie de "Assert". Lo hará, dependiendo de los valores de un archivo de configuración, sin importar las opciones de compilación de depuración / liberación:

  • registrar el error
  • abrir un cuadro de mensaje con un "Hola, tienes un problema"
  • abrir un cuadro de mensaje con un "Hola, tienes un problema, ¿quieres depurar?"

Tanto en el desarrollo como en las pruebas, esto permite al usuario identificar el problema exactamente cuando se detecta y no después (cuando a algún código le importa el valor de retorno o dentro de una captura).

Es fácil de agregar al código heredado. Por ejemplo:

void doSomething(CMyObject * p, int iRandomData) { // etc. }

lidera un tipo de código similar a:

void doSomething(CMyObject * p, int iRandomData) { if(iRandomData < 32) { MY_RAISE_ERROR("Hey, iRandomData " << iRandomData << " is lesser than 32. Aborting processing") ; return ; } if(p == NULL) { MY_RAISE_ERROR("Hey, p is NULL !/niRandomData is equal to " << iRandomData << ". Will throw.") ; throw std::some_exception() ; } if(! p.is Ok()) { MY_RAISE_ERROR("Hey, p is NOT Ok!/np is equal to " << p->toString() << ". Will try to continue anyway") ; } // etc. }

(Tengo macros similares que solo están activas en depuración).

Tenga en cuenta que en la producción, el archivo de configuración no existe, por lo que el cliente nunca ve el resultado de esta macro ... Pero es fácil activarlo cuando sea necesario.

Conclusión

Cuando codifica usando códigos de retorno, se está preparando para el fracaso y espera que su fortaleza de pruebas sea lo suficientemente segura.

Cuando codifica usando la excepción, sabe que su código puede fallar, y generalmente pone la captura de contrafuego en la posición estratégica elegida en su código. Pero, por lo general, su código es más sobre "lo que debe hacer" y luego "lo que temo que sucederá".

Pero cuando codifica, debe usar la mejor herramienta a su disposición y, a veces, es "Nunca oculte un error y muéstrese lo antes posible". La macro que hablé arriba sigue esta filosofía.

Mi pregunta es qué prefieren la mayoría de los desarrolladores para el manejo de errores, excepciones o códigos de retorno de error. Por favor, especifique el idioma (o familia de idioma) y por qué prefiere uno sobre el otro.

Estoy preguntando esto por curiosidad. Personalmente, prefiero los códigos de retorno de error, ya que son menos explosivos y no obligan al código de usuario a pagar la penalización de rendimiento de excepción si no lo desean.

actualización: gracias por todas las respuestas! Debo decir que aunque no me gusta la imprevisibilidad del flujo de código con excepciones. La respuesta sobre el código de retorno (y sus manejadores de hermano mayor) agrega mucho ruido al código.


Con cualquier compilador decente o entorno de tiempo de ejecución, las excepciones no incurren en una penalización significativa. Es más o menos como una declaración GOTO que salta al manejador de excepciones. Además, tener excepciones capturadas por un entorno de tiempo de ejecución (como la JVM) ayuda a aislar y corregir un error mucho más fácil. Tomaré una NullPointerException en Java sobre un segfault en C cualquier día.


Creo que los códigos de retorno aumentan el ruido del código. Por ejemplo, siempre odié la apariencia del código COM / ATL debido a los códigos de retorno. Tenía que haber un cheque HRESULT para cada línea de código. Considero que el código de retorno de error es una de las malas decisiones tomadas por los arquitectos de COM. Hace que sea difícil hacer un agrupamiento lógico del código, por lo que la revisión del código se vuelve difícil.

No estoy seguro acerca de la comparación de rendimiento cuando hay una verificación explícita del código de retorno en cada línea.


De acuerdo con el Capítulo 7 titulado "Excepciones" en las Pautas de diseño de marcos: Convenciones, modismos y patrones para bibliotecas .NET reutilizables , se dan numerosas razones de por qué es necesario usar excepciones sobre valores de retorno para marcos OO como C #.

Quizás esta es la razón más convincente (página 179):

"Las excepciones se integran bien con los lenguajes orientados a objetos. Los lenguajes orientados a objetos tienden a imponer restricciones a las firmas de miembros que no son impuestas por funciones en lenguajes no OO. Por ejemplo, en el caso de constructores, sobrecargas de operadores y propiedades, el desarrollador no tiene elección en el valor de retorno. Por esta razón, no es posible estandarizar en informes de errores basados ​​en valores devueltos para marcos orientados a objetos. Un método de informe de error, como excepciones, que está fuera de banda de la firma del método es la única opción " .


En Java, uso (en el siguiente orden):

  1. Diseño por contrato (asegurando que se cumplan las condiciones previas antes de intentar cualquier cosa que pueda fallar). Esto capta la mayoría de las cosas y devuelvo un código de error para esto.

  2. Devolver códigos de error mientras se procesa el trabajo (y realizar la reversión si es necesario).

  3. Excepciones, pero estas se usan solo para cosas inesperadas.


Escribí una publicación en el blog sobre esto hace un tiempo.

El rendimiento general de lanzar una excepción no debe jugar ningún papel en su decisión. Si lo estás haciendo bien, después de todo, una excepción es excepcional .


Hay muchas razones para preferir Excepciones sobre el código de retorno:

  • Por lo general, para facilitar la lectura, las personas intentan minimizar el número de declaraciones de retorno en un método. Al hacerlo, las excepciones impiden hacer un trabajo extra mientras se está en un estado incorrecto, y así evitar dañar potencialmente más datos.
  • La excepción es generalmente más detallada y más fácil de ampliar que el valor de retorno. Suponga que un método devuelve un número natural y que utiliza números negativos como código de retorno cuando ocurre un error, si el alcance de su método cambia y ahora devuelve números enteros, tendrá que modificar todas las llamadas al método en lugar de simplemente ajustar un poco La excepción.
  • Excepciones permite separar con mayor facilidad el manejo de errores del comportamiento normal. Permiten garantizar que algunas operaciones se realicen de alguna manera como una operación atómica.

Las excepciones no son para el manejo de errores, IMO. Las excepciones son solo eso; eventos excepcionales que no esperabas. Usar con precaución, digo.

Los códigos de error pueden estar bien, pero devolver 404 o 200 desde un método es malo, IMO. Use enums (.Net) en su lugar, que hace que el código sea más legible y más fácil de usar para otros desarrolladores. Además, no es necesario mantener una tabla con los números y las descripciones.

También; el patrón try-catch-finally es un antipatrón en mi libro. Probar finalmente puede ser bueno, try-catch también puede ser bueno, pero try-catch-finally nunca es bueno. try-finally muchas veces puede ser reemplazado por una instrucción "using" (patrón IDispose), que es mejor IMO. Y Try-catch, donde realmente atrapa una excepción que puede manejar, es buena, o si hace esto:

try{ db.UpdateAll(somevalue); } catch (Exception ex) { logger.Exception(ex, "UpdateAll method failed"); throw; }

Así que mientras permita que la excepción continúe burbujeando, está bien. Otro ejemplo es esto:

try{ dbHasBeenUpdated = db.UpdateAll(somevalue); // true/false } catch (ConnectionException ex) { logger.Exception(ex, "Connection failed"); dbHasBeenUpdated = false; }

Aquí realmente manejo la excepción; Lo que hago fuera del try-catch cuando falla el método de actualización es otra historia, pero creo que ya se mencionó. :)

¿Por qué entonces es try-catch-finally un anti-patrón? Este es el por qué:

try{ db.UpdateAll(somevalue); } catch (Exception ex) { logger.Exception(ex, "UpdateAll method failed"); throw; } finally { db.Close(); }

¿Qué sucede si el objeto db ya se ha cerrado? ¡Se lanza una nueva excepción y debe ser manejada! Esta es mejor:

try{ using(IDatabase db = DatabaseFactory.CreateDatabase()) { db.UpdateAll(somevalue); } } catch (Exception ex) { logger.Exception(ex, "UpdateAll method failed"); throw; }

O bien, si el objeto db no implementa IDisposable, haga esto:

try{ try { IDatabase db = DatabaseFactory.CreateDatabase(); db.UpdateAll(somevalue); } finally{ db.Close(); } } catch (DatabaseAlreadyClosedException dbClosedEx) { logger.Exception(dbClosedEx, "Database connection was closed already."); } catch (Exception ex) { logger.Exception(ex, "UpdateAll method failed"); throw; }

¡Son mis 2 centavos de todos modos! :)


Las excepciones solo deben devolverse donde sucede algo que no esperabas.

El otro punto de las excepciones, históricamente, es que los códigos de retorno son intrínsecamente propietarios, a veces se puede devolver un 0 desde una función C para indicar el éxito, a veces -1, o cualquiera de ellos para un fracaso con 1 para un éxito. Incluso cuando se enumeran, las enumeraciones pueden ser ambiguas.

Las excepciones también pueden proporcionar mucha más información, y específicamente deletrear bien ''Algo salió mal, esto es qué, un rastro de pila y alguna información de apoyo para el contexto''

Una vez dicho esto, un código de retorno bien enumerado puede ser útil para un conjunto conocido de resultados, un simple ''heres n resultados de la función, y simplemente corrió de esta manera''


Los códigos de retorno me fallan la prueba " Pit of Success " casi todas las veces.

  • Es demasiado fácil olvidarse de verificar un código de retorno y luego tener un error de arenque rojo más adelante.
  • Los códigos de retorno no tienen la gran información de depuración como call stack, excepciones internas.
  • Los códigos de retorno no se propagan, lo que, junto con el punto anterior, tiende a generar un registro de diagnóstico excesivo e interconectado en lugar de iniciar sesión en un lugar centralizado (controladores de excepciones de aplicación y de nivel de subprocesos).
  • Los códigos de retorno tienden a generar código desordenado en forma de bloques anidados ''si''
  • El tiempo invertido por el desarrollador en depurar un problema desconocido que de otra manera hubiera sido una excepción obvia (pozo del éxito) ES costoso.

En cuanto a rendimiento:

  • Las excepciones pueden ser computacionalmente caras RELATIVAS a no arrojar nada, pero se llaman EXCEPCIONES por alguna razón. Las comparaciones de velocidad siempre logran asumir una tasa de excepción del 100% que nunca debería ser el caso. Incluso si una excepción es 100 veces más lenta, ¿cuánto importa realmente si solo ocurre el 1% del tiempo?
  • A menos que estemos hablando de aritmética de punto flotante para aplicaciones gráficas, o algo similar, los ciclos de CPU son baratos en comparación con el tiempo del desarrollador.
  • El costo desde una perspectiva de tiempo conlleva el mismo argumento. En relación con las consultas de la base de datos o las llamadas al servicio web o las cargas de archivos, el tiempo de aplicación normal reducirá el tiempo de excepción. Las excepciones fueron casi sub-MICROsegundos en 2006
    • Me atrevo a cualquiera que trabaje en .net, para configurar su depurador para que rompa todas las excepciones y deshabilite solo mi código y vea cuántas excepciones ya están sucediendo que usted ni siquiera conoce.

Mi preferencia (en C ++ y Python) es usar excepciones. Las instalaciones proporcionadas por el idioma lo convierten en un proceso bien definido para plantear, atrapar y (si es necesario) volver a lanzar excepciones, haciendo que el modelo sea fácil de ver y usar. Conceptualmente, es más limpio que los códigos de retorno, en el sentido de que las excepciones específicas se pueden definir por sus nombres, y tienen información adicional que los acompaña. Con un código de retorno, está limitado al valor de error (a menos que desee definir un objeto ReturnStatus o algo así).

A menos que el código que está escribiendo sea de tiempo crítico, la sobrecarga asociada con el desenrollado de la pila no es lo suficientemente importante como para preocuparse.


Mi regla general en el argumento de la excepción frente al código de retorno:

  • Use códigos de error cuando necesite localización / internacionalización: en .NET, podría usar estos códigos de error para hacer referencia a un archivo de recursos que luego mostrará el error en el idioma apropiado. De lo contrario, use excepciones
  • Use excepciones solo para errores que son realmente excepcionales. Si es algo que sucede con bastante frecuencia, use un booleano o un código de error enum.

No creo que los códigos de retorno sean menos feos que las excepciones. Con la excepción, tienes try{} catch() {} finally {} donde al igual que con los códigos de retorno tienes if(){} . Solía ​​temer las excepciones por las razones dadas en la publicación; no sabes si el puntero necesita ser borrado, ¿qué tienes? Pero creo que tienes los mismos problemas cuando se trata de los códigos de retorno. No conoce el estado de los parámetros a menos que sepa algunos detalles sobre la función / método en cuestión.

De todos modos, debes manejar el error si es posible. También puede permitir que una excepción se propague al nivel superior, ya que ignora un código de retorno y deja que el programa segmente la falla.

Me gusta la idea de devolver un valor (¿enumeración?) Para obtener resultados y una excepción para un caso excepcional.


No me gustan los códigos de retorno porque hacen que el siguiente patrón se desarrolle en todo tu código

CRetType obReturn = CODE_SUCCESS; obReturn = CallMyFunctionWhichReturnsCodes(); if (obReturn == CODE_BLOW_UP) { // bail out goto FunctionExit; }

Pronto, una llamada a un método que consta de 4 llamadas a funciones se hincha con 12 líneas de manejo de errores. Algunas de las cuales nunca sucederán. Si y cambian los casos abundan.

Las excepciones son más claras si las usa bien ... para señalar eventos excepcionales ... después de los cuales la ruta de ejecución no puede continuar. A menudo son más descriptivos e informativos que los códigos de error.

Si tiene múltiples estados después de una llamada a un método que debe manejarse de manera diferente (y no son casos excepcionales), use códigos de error o parámetros externos. Aunque Personaly, he encontrado que esto es raro ...

He buscado un poco sobre el contraargumento de ''penalización por rendimiento'' ... más en el mundo C ++ / COM, pero en los idiomas más nuevos, creo que la diferencia no es tanta. En cualquier caso, cuando algo explota, las preocupaciones sobre el rendimiento quedan relegadas a un segundo plano :)


Para un lenguaje como Java, iría con Exception porque el compilador genera un error de tiempo de compilación si no se manejan las excepciones. Esto fuerza a la función de llamada a manejar / lanzar las excepciones.

Para Python, estoy más en conflicto. No hay compilador, por lo que es posible que la persona que llama no maneje la excepción lanzada por la función que conduce a las excepciones de tiempo de ejecución. Si usa códigos de retorno, es posible que tenga un comportamiento inesperado si no se maneja correctamente y si usa excepciones, es posible que obtenga excepciones de tiempo de ejecución.


Prefiero usar excepciones para manejo de errores y valores (o parámetros) de retorno como el resultado normal de una función. Esto proporciona un esquema de manejo de errores fácil y consistente y, si se hace correctamente, proporciona un código mucho más limpio.


Solo uso excepciones, sin códigos de retorno. Estoy hablando de Java aquí.

La regla general que sigo es si tengo un método llamado doFoo() entonces se deduce que si no hace "hacer foo", por así doFoo() , entonces algo excepcional ha sucedido y se debe lanzar una excepción.


Tengo un conjunto simple de reglas:

1) Usa códigos de retorno para las cosas que esperas que responda tu llamador inmediato.

2) Use excepciones para errores de alcance más amplio, y se puede esperar razonablemente que sean manejados por muchos niveles por encima de la persona que llama para que el conocimiento del error no tenga que filtrarse a través de muchas capas, haciendo que el código sea más complejo.

En Java, solo utilicé excepciones no marcadas, las excepciones comprobadas terminaron siendo solo otra forma de código de retorno y en mi experiencia la dualidad de lo que podría ser "devuelto" por una llamada a un método generalmente era más un inconveniente que una ayuda.


Un gran consejo que recibí de The Pragmatic Programmer fue algo así como "tu programa debería ser capaz de realizar todas sus funciones principales sin usar excepciones en absoluto".


Una cosa que temo acerca de las excepciones es que lanzar una excepción arruinará el flujo de código. Por ejemplo, si lo haces

void foo() { MyPointer* p = NULL; try{ p = new PointedStuff(); //I''m a module user and I''m doing stuff that might throw or not } catch(...) { //should I delete the pointer? } }

O peor aún, ¿qué pasa si eliminé algo que no debería tener, pero me lanzaron a atrapar antes de hacer el resto de la limpieza? Lanzar puso mucho peso en el usuario pobre en mi humilde opinión.


Una de las grandes diferencias es que las excepciones lo obligan a manejar un error, mientras que los códigos de retorno de error no se verifican.

Los códigos de retorno de error, si se usan en exceso, también pueden causar un código muy feo con muchas pruebas similares a esta forma:

if(function(call) != ERROR_CODE) { do_right_thing(); } else { handle_error(); }

Personalmente, prefiero usar excepciones para errores que DEBERÍAN o DEBERÍAN aplicarse el código de llamada, y solo usar códigos de error para "fallas esperadas" donde la devolución de algo es realmente válida y posible.


Utilizo Excepciones en python en circunstancias excepcionales y no excepcionales.

A menudo es bueno poder utilizar una excepción para indicar que "no se pudo realizar la solicitud", en lugar de devolver un valor de error. Significa que usted / siempre / sabe que el valor de retorno es del tipo correcto, en lugar de arbitrariamente None o NotFoundSingleton o algo así. Aquí hay un buen ejemplo de dónde prefiero usar un controlador de excepción en lugar de un condicional en el valor de retorno.

try: dataobj = datastore.fetch(obj_id) except LookupError: # could not find object, create it. dataobj = datastore.create(....)

El efecto secundario es que cuando se ejecuta un datastore.fetch (obj_id), nunca tiene que verificar si su valor de retorno es Ninguno, se obtiene ese error inmediatamente de forma gratuita. Esto es contrario al argumento, "su programa debería poder realizar todas sus funciones principales sin usar excepciones en absoluto".

Aquí hay otro ejemplo de donde las excepciones son ''excepcionalmente'' útiles, con el fin de escribir código para tratar con el sistema de archivos que no está sujeto a condiciones de carrera.

# wrong way: if os.path.exists(directory_to_remove): # race condition is here. os.path.rmdir(directory_to_remove) # right way: try: os.path.rmdir(directory_to_remove) except OSError: # directory didn''t exist, good. pass

Una llamada al sistema en lugar de dos, sin condiciones de carrera. Este es un ejemplo pobre porque obviamente esto fracasará con un OSError en más circunstancias de lo que el directorio no existe, pero es una solución "suficientemente buena" para muchas situaciones estrechamente controladas.


Yo uso ambos en realidad.

Utilizo códigos de retorno si se trata de un error conocido y posible. Si se trata de un escenario que sé que puede y va a suceder, entonces hay un código que se envía de vuelta.

Las excepciones se usan únicamente para cosas que NO estoy esperando.