Why doesn't F# naturally support a try/with/finally block?
Doesn't it make sense to try something, deal with whatever exception it throws, at least to log the exception, and then be sure that some code executes after all that?
Sure, we can do
try
try
...
with ex -> ...
finally
...
But that seems too artificial, it clearly demonstrates that "F# is against try/with/finally". Why is that?
As somebody already mentioned, you would usually use try-with-finally
to make sure that you properly release all resources in case of an exception. I think in most of the cases you can do this more easily using the use
keyword:
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
I think this is mostly the reason why you don't need try-with-finally
as often as you would in other languages. But of course, there are some situations where you may need it (but you could of course avoid that by creating instance of IDisposable
using object expressions (which is syntactically very easy). But I think this is so rare that the F# team doesn't really need to worry about this.
Orthogonality? You can simply nest a try-with inside a try-finally, as you show. (This is what happens at the IL level anyway, I think.)
That said, try-with-finally is something that we may consider in a future version of the language.
Personally I have only run into wanting it a couple times, but when you do need it, it is a little bothersome to have to do the extra nesting/indent. In general I find that I rarely write exception handling code, and it's usually just one or the other (e.g. a finally to restore an invariant or other transactional semantics, or a 'catch' near the top of an app to log an exception or show the user diagnostics).
But I don't think there's a lot to 'read in to' regarding the language design here.
Without going into great detail because the great details are in
Expert .NET 2.0 IL Assembler by Serge Lidin
See: Ch. 14, Managed Exception Handling
"The finally and fault handlers cannot peacefully coexist with other handlers, so if a guarded block has a finally or fault handler, it cannot have anything else. To combine a finally or fault handler with other handlers, you need to nest the guarded and handler bocks within other guarded blocks, ..., so that each finally or fault handler has its own personal guarded block."
pg. 300
A try/catch uses a fault handler and a try/finally uses a finally handler.
See: ILGenerator.BeginFaultBlock Method
If you emit a fault handler in an exception block that also contains a catch handler or a finally handler, the resulting code is unverifiable.
So, all of the .net languages could be consider to be using syntactic surgar and since F# is so new, they just haven't implemented it yet. No harm no fould.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With