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

C# 6.0 feature: Exception Filters #2

Merged
merged 6 commits into from
Oct 21, 2021
Merged

Conversation

BillWagner
Copy link
Member

Add "when" as a contextual keyword.
Update grammar for exception filters
Add description of exception filters.

@BillWagner BillWagner force-pushed the feature-exception-filter branch 2 times, most recently from d64e5ea to 8d415d3 Compare October 26, 2020 18:15
@BillWagner
Copy link
Member Author

@jskeet This feature PR is ready for committee review.

@jskeet
Copy link
Contributor

jskeet commented Oct 26, 2020

Right... we should probably have an alias that we can assign as a reviewer which will ping everyone. Not quite sure how that works though, and I'm signing off for the night... I can look tomorrow though.

@BillWagner BillWagner mentioned this pull request Nov 30, 2020
@jskeet jskeet added the meeting: discuss This issue should be discussed at the next TC49-TG2 meeting label Dec 9, 2020
@Nigel-Ecma
Copy link
Contributor

In the diff's I'm seeing changed body text about exception filters and the non-terminal exception_filter but I'm not seeing any grammar rules for the non-terminal. Is something missing or is my browser having fun with me?

@RexJaeschke
Copy link
Contributor

RexJaeschke commented Dec 12, 2020

I originally created this proposal in the conversion-to-markdown repo as PR107. It had two commits, to update statements.md and lexical-structure.md. Later, @BillWagner force-pushed that work over here, but as best as I can tell, the front part of the statements.md commit got lost, and needs to be put back. (Bill, being a novice GitHub user, rather than trying to figure our how to salvage that missing text from the commit, I'm showing it [the complete/replacement try_statement grammar] here, so Nigel can continue his review.)

try_statement
    : 'try' block catch_clause+
    | 'try' block finally_clause
    | 'try' block catch_clause+ finally_clause
    ;
catch_clause
    : 'catch' exception_specifier? exception_filter?  block
    ;
exception_specifier
    : '(' type identifier? ')'
    ;
exception_filter
    : 'when' '(' expression ')'
    ;
finally_clause
    : 'finally' block
    ;

@BillWagner - I updated this PR with the above grammar on 2021/07/15

@Nigel-Ecma
Copy link
Contributor

Nigel-Ecma commented Dec 13, 2020

Thanks for the proposed grammar Rex, makes it easier :-)

An observation on the grammar, I'll decide later whether it is more than that (i.e. this is my note pad!)

For comparison this is the current grammar in ANTLR:

try_statement
    : 'try' block catch_clauses
    | 'try' block catch_clauses* finally_clause
    ;
catch_clauses
    : specific_catch_clause+
    | specific_catch_clause* general_catch_clause
    ;
specific_catch_clause
    : 'catch' '(' type identifier? ')'  block
    ;
general_catch_clause
    : 'catch' block
    ;
finally_clause
    : 'finally' block
    ;

Notes:

  • In the original grammar try_statement syntactically enforces that there must be at least one catch or finally in a try, and finally must be last if there is one.
  • Similarly catch_clauses syntactically enforces that a general_catch_clause must be last
  • In the proposed grammar try_statement is expanded to three alternatives (the syntax is equivalent to the original), maybe to match the text’s “There are three possible forms...”?, and continues to syntactically enforce the same conditions as the original grammar
  • However that a catch clause without any exception_specifier or exception_filter (the original’s general_catch_clause) must be last is no longer enforced syntactically and moves to the text as a semantic rule.

Conclusion? None, for now just an observation...

standard/statements.md Outdated Show resolved Hide resolved
standard/statements.md Outdated Show resolved Hide resolved
@Nigel-Ecma
Copy link
Contributor

Lines 1170 - 1184/5 (I couldn't figure out how to comment on a range of lines which ends in an unchanged line, on the other hand starting with an unchanged line is straightforward):

In trying to merge the introduction of exception clauses into this built list algorithm the grammar goes wrong (e.g. "The first ... is" -> "If a ... it is" - the it is missing), and clauses are also "considered a match" and then "not a match" or re-"considered a match". Rather than try to address such things piecemeal here is a first attempt, probably too nested, to describe the revised algorithm with bullet points, including dropping some overly (subjective) repetitive bits:

  • Control is transferred to the try block.
  • When and if control reaches the end point of the try block:
    • If the try statement has a finally block, the finally block is executed.
    • Control is transferred to the end point of the try statement.
  • Otherwise if an exception is propagated to the try statement during execution of the try block:
    • If there are catch clauses then:
      • The catch clauses are examined in lexical order seeking a suitable handler for the exception.
      • If a catch clause being examined either: does not specify a type; or specifies the exception type or a base type of the exception type then:
        • If the clause declares an exception variable, the exception object is assigned to the exception variable.
        • If the clause declares an exception filter, the filter is evaluated. If it evaluates to false, the clause is not a match, and the search continues.
        • Otherwise, the clause is a match, and control is transferred to the matching catch block.
          • When and if control reaches the end point of the catch block:
            • If the try statement has a finally block, the finally block is executed.
            • Control is transferred to the end point of the try statement.
          • If an exception is propagated to the try statement during execution of the catch block:
            • If the try statement has a finally block, the finally block is executed.
            • The exception is propagated to the next enclosing try statement.
      • If the search ends without finding a matching catch clause then:
        • If the try statement has a finally block, the finally block is executed.
        • The exception is propagated to the next enclosing try statement.
    • Otherwise if the try statement has no catch clauses:
      • If the try statement has a finally block, the finally block is executed.
      • The exception is propagated to the next enclosing try statement.

@@ -1103,17 +1103,17 @@ There are three possible forms of `try` statements:
- A `try` block followed by a `finally` block.
- A `try` block followed by one or more `catch` blocks followed by a `finally` block.
Copy link
Contributor

@Nigel-Ecma Nigel-Ecma Dec 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This original para & bullet list are redundant, the forms are not referenced elsewhere and it simply a prose description of the try_statement production. In the original that production only has two alternatives:

try_statement
    : 'try' block catch_clauses
    | 'try' block catch_clauses* finally_clause
    ;

while the proposal expands this to three, maybe just to match this (original) bullet list, though the described syntax is identical.

The descriptions of other statements do not generally start with a prose description of the statement structure, so there is not a pattern being followed here, however the switch statement does.

Option 1: 😄 Remove this para & bullet list

Option 2: 🚀 Follow the model of the switch statement and replaced with a more succinct description which doesn't introduce "forms". Something like:

A try_statement consists of the keyword try followed by a block, then zero or more catch_clauses, then an optional finally_clause. There must be at least one catch_clause or a finally_clause.

Option 3: 👀 Leave as is

If Option 1 or 2 is chosen then the grammar for try_statement can revert to the two alternative original version, of option 3 is chosen then there is a small argument for the proposed three alternative version.

@Nigel-Ecma
Copy link
Contributor

A slightly less indented replacement for lines 1170 - 1184/5:

  • Control is transferred to the try block.
  • If control reaches the end point of the try block without an exception being propagated then:
    • If the try statement has a finally block, the finally block is executed.
    • Control is transferred to the end point of the try statement.
  • Otherwise (as an exception has been propagated):
    • The catch clauses, if any, are examined in lexical order seeking the first match for the exception. A catch clause is a match:
      • If: the clause does not specify a type or specifies the exception type or a base type of the exception type
      • And: if the clause contains an exception filter then; after assigning the exception object to the exception variable, if any; evaluation of the exception filter returns true
    • If a matching catch clause is found control is transferred to the corresponding catch block.
      • If control reaches the end point of the catch block without an exception being propagated then:
        • If the try statement has a finally block, the finally block is executed.
        • Control is transferred to the end point of the try statement.
      • Otherwise (as an exception has been propagated):
        • If the try statement has a finally block, the finally block is executed.
        • The exception is propagated to the next enclosing try statement.
    • If the search ends without finding a matching catch clause then:
      • If the try statement has a finally block, the finally block is executed.
      • The exception is propagated to the next enclosing try statement.

I can't say I like this bulleted prose description of the semantics and none of the versions (original, proposal, my two attempts to fix and clean it up) include what happens if an exception is thrown during the finally block – that is covered in a following para – so they are all incomplete...

Incorporating the missing bits would further complicate/nest the bullets, maybe a sequence of short paras would be better, and I say that as someone who generally prefers the economy of bulleted lists to the verbosity of prose! ;-)

@jskeet
Copy link
Contributor

jskeet commented Dec 16, 2020

Yes, I think a sequence of short paragraphs would make sense here. I would suggest that we don't merge this PR, but instead create a parallel PR that also addresses #53. We can then compare the two easily and see which we like better.

@jskeet jskeet removed the meeting: discuss This issue should be discussed at the next TC49-TG2 meeting label Feb 5, 2021
@jskeet
Copy link
Contributor

jskeet commented Feb 5, 2021

(Removed label so that we can reapply it when the parallel PR has been created.)

@jskeet
Copy link
Contributor

jskeet commented Mar 5, 2021

@Nigel-Ecma: Currently this is assigned to you - did you volunteer to create the parallel PR mentioned above?

@Nigel-Ecma
Copy link
Contributor

Nigel-Ecma commented Mar 8, 2021

@jskeet: Not that I recall... I'll have to review the issues and threads to see if I've got content for any parallel PR.

@BillWagner
Copy link
Member Author

For discussion tomorrow: If @Nigel-Ecma doesn't have a draft, I can take the notes and content here and create the new PR.

@RexJaeschke RexJaeschke added this to the C# 6 milestone Mar 17, 2021
@gafter gafter self-assigned this Jun 30, 2021
@gafter gafter self-requested a review June 30, 2021 21:22
@jskeet jskeet added the meeting: discuss This issue should be discussed at the next TC49-TG2 meeting label Jun 30, 2021
Add "when" as a contextual keyword.
Update grammar for exception filters
Add description of exception filters.
@BillWagner
Copy link
Member Author

Status update:

Most of the comments above have been addressed. The following are still unresolved:

gafter
gafter previously requested changes Jul 28, 2021
Copy link
Member

@gafter gafter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some mall changes suggested.

standard/statements.md Outdated Show resolved Hide resolved
standard/statements.md Outdated Show resolved Hide resolved
standard/statements.md Outdated Show resolved Hide resolved
standard/statements.md Outdated Show resolved Hide resolved

When a `catch` clause specifies both a *class_type* and an *Identifier*, an ***exception variable*** of the given name and type is declared. The exception variable corresponds to a local variable with a scope that extends over the `catch` block. During execution of the `catch` block, the exception variable represents the exception currently being handled. For purposes of definite assignment checking, the exception variable is considered definitely assigned in its entire scope.
When a `catch` clause specifies both a *class_type* and an *Identifier*, an ***exception variable*** of the given name and type is declared. The exception variable corresponds to a local variable with a scope that extends over the `catch` block. During execution of the *exception_filter* and `catch` block, the exception variable represents the exception currently being handled. For purposes of definite assignment checking, the exception variable is considered definitely assigned in its entire scope.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems odd that the exception is already "being handled" during execution of the exception_filter even though an "exception handler" has not been located yet.

@Nigel-Ecma
Copy link
Contributor

Nigel-Ecma commented Sep 20, 2021

Back in the mists of time (Dec 20) I remarked that the revised grammar which adds exception filters (when) also removed the syntactic requirement that a general_catch_clause if present must be the last one; leaving it as an in-text requirement only.

Being of the view that a reference grammar should be as precise as reasonable (while a compiler may use a more lenient grammar to assist error messages and recovery) here is a version of the grammar which maintains the syntactic restriction:

try_statement
    : 'try' block catch_clauses
    | 'try' block catch_clauses* finally_clause
    ;
catch_clauses
    : specific_catch_clause+
    | specific_catch_clause* general_catch_clause
    ;
specific_catch_clause
    : 'catch' exception_specifier exception_filter? block
    : 'catch' exception_filter block
    ;
exception_specifier
    : '(' type identifier? ')'
    ;
exception_filter
    : 'when' '(' boolean_expression ')'
    ;
general_catch_clause
    : 'catch' block
    ;
finally_clause
    : 'finally' block
    ;

Notes:

  1. I left the origianal 2-alternative version of try_statement rather than replace the the equivalent 3-alternative version
  2. I changed expression to boolean_expression in exception_filter as that matches the purpose of boolean_expression. A matching change to the list of places boolean_expression occurs would be needed to §12.21 Boolean expressions.

I’ll argue this version of the grammar is better as a reference grammar as it embodies all of the syntactic requirements.

(And if case someone asks, sorry I haven't come up with a series of short paras to replace the nested bullets, over to a wordsmith ;-))

@jskeet
Copy link
Contributor

jskeet commented Oct 20, 2021

Recording my vote here for option 2 described above - a succinct description.

@jskeet
Copy link
Contributor

jskeet commented Oct 20, 2021

Further actions:

Copy link
Contributor

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved after the grammar and "option 2" changes have been applied.

@BillWagner BillWagner self-assigned this Oct 20, 2021
@BillWagner BillWagner dismissed gafter’s stale review October 20, 2021 20:43

All comments from Neal have been addressed.

Update the grammar and the description of the `try` statement.  See #2 (comment)
@BillWagner BillWagner merged commit 64a39bf into draft-v6 Oct 21, 2021
@BillWagner BillWagner deleted the feature-exception-filter branch October 21, 2021 20:06
brendasmith8 added a commit to brendasmith8/csharp-standard that referenced this pull request Apr 24, 2023
* feature exception filters

Add "when" as a contextual keyword.
Update grammar for exception filters
Add description of exception filters.

* respond to suggestions

* restore grammar updates

* Apply suggestions from code review

Co-authored-by: Neal Gafter <[email protected]>

* Update recommended at meeting

Update the grammar and the description of the `try` statement.  See dotnet/csharpstandard#2 (comment)

Co-authored-by: Neal Gafter <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meeting: discuss This issue should be discussed at the next TC49-TG2 meeting
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants