2010-01-16 20 views
8

¿Por qué F # naturalmente no admite un bloque try/with/finally?F # construcciones de manejo de excepciones

¿No tiene sentido para tratar algo, acuerdo con lo que arroja una excepción, al menos para registrar la excepción, y luego asegúrese de que algún código se ejecuta después de todo eso?

Claro, podemos hacer

try 
    try 
     ... 
    with ex -> ... 
finally 
    ... 

pero que parece demasiado artificial, demuestra claramente que "F # está en contra de try/con/por último". ¿Porqué es eso?

+2

¿Es artificial? Solo veo una palabra clave redundante de tres letras. C++ no es acusado de estar "en contra de las variables" porque tiene que escribir un "int" redundante. Además, no estoy seguro de cómo se usan las excepciones, pero cuando estoy programando, las excepciones no son para el registro. Si tiene un valor para ofrecer en el nivel en el que se encuentra cuando ocurre una excepción, devuelva ese valor; de lo contrario, permita que la excepción suba aún más, pero no veo qué registro tiene que ver con eso ... –

+4

@Pascal Cuoq: por favor, no hagas suposiciones sobre ** cómo ** utilizo las excepciones. Si deseo registrar una excepción por cualquier motivo, no implica automáticamente que use excepciones para el registro, ya que su comentario implica que sí. Además, esta no es una pregunta sobre CÓMO manejar una excepción y QUÉ HACER, pero es simplemente (como se dijo dos veces en la pregunta): ** ¿POR QUÉ no admite F/try/with/finally **? –

Respuesta

12

Como alguien ya ha mencionado, generalmente usaría try-with-finally para asegurarse de liberar adecuadamente todos los recursos en caso de una excepción. Creo que en la mayoría de los casos se puede hacer esto más fácilmente usando la palabra clave use:

let input = 
    try 
    use stream = new FileStream("C:\temp\test.txt"); 
    use rdr = new StreamReader(stream); 
    Some(rdr.ReadToEnd()) 
    with :? IOException as e -> 
    logError(e) 
    None 

creo que esto es principalmente la razón por la que no es necesario try-with-finally tan a menudo como lo haría en otros idiomas. Pero, por supuesto, hay algunas situaciones en las que puede necesitarlo (pero puede evitarlo creando una instancia de IDisposable usando expresiones de objeto (que es sintácticamente muy fácil). Pero creo que esto es tan raro que el equipo de F # en realidad no se tenga que preocuparse por este

0

Pero eso parece demasiado artificial, demuestra claramente que "F # está contra try/with/finally". ¿Porqué es eso?

Supongo que F # podría ser "contra" el manejo de excepciones en absoluto. Por el bien de la interoperabilidad .NET, tiene que soportarlos, pero básicamente, no hay manejo de excepciones * en la programación funcional.

Lanzar/atrapar excepciones significa realizar "saltos a ninguna parte" que ni siquiera son notados por el sistema de tipos que es fundamentalmente contrario a la filosofía funcional.

Puede usar código puramente funcional (monádico) para ajustar excepciones. Todos los errores se manejan a través de valores, en términos del sistema de tipos subyacente y sin saltos/efectos secundarios.

En lugar de escribir una función

let readNumber() : int = ... 

que pueden lanzar excepciones arbitrarias, podrás limitan a afirmar

let readNumber() : int option = ... 

lo que hace que este punto borrará automáticamente por su declaración de tipo.

* Esto no significa que no manejemos situaciones excepcionales, es solo el tipo de manejo de excepciones en .NET/C++.

+0

No estoy del todo de acuerdo con la afirmación de que "no hay una excepción en la programación funcional". Los programadores de ML han hecho (buen) uso de excepciones desde los comienzos del lenguaje, incluso cuando escriben funciones puras. Es cierto que los sistemas de tipo comúnmente utilizados no los toman en cuenta, pero es un problema tan pequeño que los sistemas perfectamente precisos que se han propuesto para manejarlos (uno de Yi et al y uno de Pessaux et al) han permanecido como experimentos académicos . –

+0

Sin embargo, cualquier excepción que arroje significa interrumpir el flujo del programa * implícitamente * que, por lo tanto, es inherentemente no funcional. – Dario

+1

en primer lugar, F # no es un lenguaje de programación puramente funcional, no está libre de efectos secundarios. El propósito de 'try/with/finally' sería separar claramente el código * main * del código * recovery * del código * finalization *, algo muy presente en el mundo no funcional. –

1

Aclararé mi comentario en esta respuesta.

  1. que sostienen que hay hay razón para suponer que desea capturar las excepciones y finalizar algunos recursos al mismo nivel. Tal vez te acostumbraste a hacerlo de esa manera en un idioma en el que era conveniente manejar ambos al mismo tiempo, pero es una coincidencia cuando sucede. La finalización es conveniente cuando no se capturan todas las excepciones del bloque interno. try...with es para atrapar excepciones para que el cálculo pueda continuar normalmente. Simplemente no hay ninguna relación entre los dos (si acaso, van en direcciones opuestas: ¿están atrapando la excepción o dejándola pasar?).

  2. ¿Por qué tiene que finalizar algo en absoluto? ¿No debería el GC administrar recursos no referenciados para usted? Ah ... pero el lenguaje está tratando de darle acceso a las primitivas del sistema que trabajan con efectos secundarios, con asignaciones y desasignaciones explícitas. Debe desasignar lo que ha asignado (en todos los casos) ...¿No deberías culpar a la interfaz podrida que proporciona el sistema en lugar de F #, que es solo el mensajero en este caso?

+0

¿Por qué CW? Si es tu opinión, no necesitas esconderte detrás. –

+0

De todos modos, F # está concebido para funcionar dentro de la plataforma .NET, y es claramente un lenguaje funcional impuro. Dicho esto, ** no, no debería culpar a la interfaz podrida que el sistema proporciona **, pero realmente me gustaría entender por qué el lenguaje parece ir en contra. –

+0

Toda la pregunta es bastante subjetiva y argumentativa, y debería haber sido CW en mi opinión. –

6

Orthogonality? Simplemente puede anidar una prueba con un intento, finalmente, como muestra. (Esto es lo que sucede en el nivel de IL de todos modos, creo).

Dicho esto, try-with-finally es algo que podemos considerar en una versión futura del lenguaje.

Personalmente, solo me he encontrado con quererlo un par de veces, pero cuando lo necesitas, es un poco molesto tener que hacer el desvío/sangría adicional. En general, encuentro que rara vez escribo código de manejo de excepciones, y generalmente solo uno o el otro (por ejemplo, finalmente restaurar una semántica invariable u otra semántica transaccional, o una 'captura' cerca de la parte superior de una aplicación para registrar una excepción o mostrar los diagnósticos del usuario).

Pero no creo que haya mucho para 'leer' con respecto al diseño del idioma aquí.

2

sin entrar en detalles porque los grandes detalles están en

Expert .NET 2.0 IL Assembler por Serge Lidin

Ver:. Ch. 14, Excepción Gestionado Manejo

"El finalmente y culpa manipuladores no puede coexistir pacíficamente con otras personas que manipulan, por lo que si un bloque vigilado tiene un manejador finalmente o culpa, no puede tener ninguna otra cosa. Para combinar una finalmente o culpa manejador con otros controladores, es necesario anidar el guardado y manejador bocks dentro de otros bloques vigilados, ..., de modo que cada finalmente o culpa controlador tiene su propio bloque vigilado personales ."

pg. 300

un try/catch utiliza un culpa manipulador y un try/finally utiliza un controlador de finalmente.

Ver: ILGenerator.BeginFaultBlock Method

Si usted emite un fallo manejador en un bloque de excepción que también contiene un controlador de captura o un fin manejador , el código resultante es no verificable.

Entonces, todos los lenguajes de .net se pueden considerar como que usan surgar sintáctico y como F # es tan nuevo, simplemente no lo han implementado todavía. No hay daño sin fould.