Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement exceptions, throw, and try/catch/finally #65

Open
masak opened this issue Oct 30, 2015 · 5 comments
Open

Implement exceptions, throw, and try/catch/finally #65

masak opened this issue Oct 30, 2015 · 5 comments

Comments

@masak
Copy link
Owner

masak commented Oct 30, 2015

Perl 6 does die and Python does raise, so there's no consensus between the two. Let's go with Java's throw, because it's a nice conjugate with catch. And it's pretty common.

So that we don't block on #32, let's also introduce an Exception(str) built-in function which can produce exception objects. After we get proper classes we can expand this into being able to create custom exception classes.

The try block can be followed by zero or more catch blocks with a declared expression parameter.

catch e {
    # ...
}

Under #33 there can be several catch blocks with type declarations.

catch e : X::SyntaxError {
    # ...
}

(Catching something which cannot possibly be caught because it's caught at earlier steps is a compile-time error. Which means actually having more than one catch block without #33 will always be a compile-time error.)

Similarly, there can be zero or one finally blocks. The semantics of which should be "the usual":

  • finally runs regardless of whether an exception was caught by the try or not
  • finally runs regardless of whether a return (or other control exception) happened inside the try
  • if a return happened inside the try, and finally also has one, the latter wins

Exceptions thrown in a catch or a finally are not caught by any of the catch blocks.

@masak
Copy link
Owner Author

masak commented Dec 6, 2015

I'm thinking we will need a .rethrow() method, especially in the #33-less regime, where we have no choice but to catch all exceptions that come our way. We then need to whitelist the ones we're interested in, and pass on the rest.

Rethrowing would be an option...

throw(e);    # because we're not interested in this e

...but not such a good one, because that involves throwing away important stacktrace between the original throw site and the catch.

@masak
Copy link
Owner Author

masak commented Mar 11, 2016

Just pointing out that dcad411 (still out in a branch) adds die (not throw) with a Val::Str (not Exception).

I think the attempt is good, but as we merge these changes into master we should normalize it to throw and the Exception. The latter is especially important so we don't end up with a lot of strings being thrown and have to go through a deprecation cycle of "old exceptions" and "new exceptions", as Python did.

masak pushed a commit that referenced this issue Mar 11, 2016
This was `die` for a short while in a branch, but #65 says we
should call it `throw`.

Also introduces the Val::Exception type, which is the only
thing you can throw. (In the branch it was Val::Str, but that's
deprecated now with extreme prejudice.)
masak pushed a commit that referenced this issue Mar 11, 2016
This was `die` for a short while in a branch, but #65 says we
should call it `throw`.

Also introduces the Val::Exception type, which is the only
thing you can throw. (In the branch it was Val::Str, but that's
deprecated now with extreme prejudice.)
masak pushed a commit that referenced this issue Mar 11, 2016
This was `die` for a short while in a branch, but #65 says we
should call it `throw`.

Also introduces the Val::Exception type, which is the only
thing you can throw. (In the branch it was Val::Str, but that's
deprecated now with extreme prejudice.)
@masak
Copy link
Owner Author

masak commented Jun 13, 2016

<masak> hm, did we ever decide something wrt `catch e {` vs `catch -> e {` ?
<sergot> hmm, we didn't decide on that catch case
<masak> what's your opinion on it?
<sergot> I like `catch e {`
<masak> yeah, there is that
<masak> and (modulo parentheses), it's pretty standard
<masak> OTOH, `catch -> e {` is consistent, and clear
<masak> and shows what's going on -- it's a block with a declared parameter
<masak> how about this -- make the `->` optional?
<masak> (and leave it to the enormous 007 community to sort out which form they like) :P
<sergot> hehehe
<sergot> sure
* masak adds this to the ticket

@masak
Copy link
Owner Author

masak commented Nov 24, 2018

Two things. First:

I think it was a mistake to ever talk about several catch blocks in a row. That only makes sense with type annotations, but the core 007 language should be entirely unaware of type annotations.

I know that sounds a bit single-minded, but I've come to the conclusion that it's nevertheless correct. There should be only one catch, like in JavaScript.

@masak
Copy link
Owner Author

masak commented Nov 26, 2018

Second:

I've become convinced that Perl 6 has it right with the CATCH phaser.

I just went back to A04 to remind myself why CATCH the phaser was decided on when basically all other modern languages went with a try/catch/finally structure. The main reason (if I'm reading between the lines correctly) is that it makes sense for the CATCH block to be lexically nested, so that it has access to all the variables of the "try" block.

I believe this to be correct. Also (and this is also being hinted as a reason in A04), having a separate try keyword denote a block doesn't carry its own weight so much — all we want to do is delimit the risky code somehow. A regular immediate block can do that (but also functions, loops, etc).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant