-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
[WIP] Exceptions, try-catch-finally #54
Comments
Would it make sense to have a more explicit support for the bottom type? Though I'm not sure how well that would work in the context of .Net, which doesn't have such a type. (There is the
I think a catch-all is usually a bad idea (at least in production code), especially if it ignores the exception. So it shouldn't be encouraged by having a succinct syntax. |
Definitely, we should consider bottom type as an option. It might be something that makes more sense on type level, than attribute level. We'll have to play around with the idea a bit.
Fair. Initially, we could only include the pattern matching syntax, then see how that plays out. |
Yeah came here to mention that Kotlin's (Also TIL that the type theory name for this concept is "bottom type".) |
I think another alternative that should be considered is something in the line of Project Midori's exception syntax. It makes it clear where exceptions can be thrown from. Though it may not fit well with the fact that C# makes too many things exceptions. I'd also like a from of checked exceptions done right. |
Introduction
Since there is not a lot of variation or redesign-choices here, I'll just propose the constructs for throwing and try-catch-finally.
Throwing construct
There is not a lot of variation here, throwing itself is an expression with the syntax:
throw expr
The returned expression type (even though the expression does not evaluate to anything, it needs a type) could be converted to any type implicitly, so type-inference does not trip up in cases like this:
Try-catch-finally
This is the point where there is a bit more variation, I'll go through all I've come across. Since all other of our control structures are expressions, it would make sense for try-catch-finally as well.
C#
Since the C# variant does not evaluate to values like expressions, it's not that interesting for us. In the most general form, try is mandatory, after that either a catch or finally block has to follow. If there is a finally block, there can be any number of catch blocks. Catch blocks try to match the exception type to the thrown exception, even allowing for a filter expression with the keyword
when
, implementing a limited pattern matching system. Full docs can be found here.Personally, I think it's a bit overengineered, and became a bit inconsistent after pattern matching hit the scene. It's a decision from the past, so there's really no one to blame for it.
F#
F# decided to introduce two different constructs, try-with and try-finally. This means, if you need all 3 blocks, you'd have to nest them (example taken from the docs):
An interesting note is that
with
(which is the equivalent ofcatch
in C#) is actually a regular pattern-matching construct, which actually makes a lot of sense. Instead of implementing specialized systems with multiple catch blocks and filters, F# simply utilizes the fact that it already has pattern matching.In
try-with
, if there are no exceptions, thetry
body is evaluated as a result, otherwise, an exception is matched inwith
, and the corresponding value is returned. Intry-finally
, only thetry
contributes to the result.Personally, I think this nesting can be really annoying, and it was a quite inelegant design.
Kotlin
In Kotlin,
try-catch-finally
is also an expression:The semantics is very simple: if there are no exceptions, the body of
try
is returned, otherwise the body of the correspondingcatch
block is returned. Thefinally
block does not contribute to the expression result.Personally, I find this the best semantics out of all. What I found odd, is that Kotlin also does multiple catch blocks instead of utilizing its pattern-matching.
Proposed for Fresh
I'd like to propose a mixture of Kotlin and F# for our construct. More precisely, the evaluation semantics of Kotlin, and the pattern matching of F#. This way we get multi-catch free, get the filters of C# free and are able to utilize everything that will be present in the language for pattern matching.
Syntax proposal:
We could even have a one-liner versions, or a version of catch that simply matches everything and returns the specified value ("swallow-all" catch):
A one-liner catch could give us the standard
try-single-catch
blocks in C#:The
finally
block does not contribute to the evaluated expression, it is simply executed after the evaluation of try-catch. Example:There can only be a single catch and a single finally block and at least one has to be present (there can't be a
try
block by itself). If there is acatch
block, it has to evaluate to a compatible type withtry
.The text was updated successfully, but these errors were encountered: