Skip to content

Commit

Permalink
C# 6.0 feature: expression bodied members (#4)
Browse files Browse the repository at this point in the history
* specification for expression bodied members

* clarify expression body

* Update classes.md

* Apply suggestions from code review

Co-authored-by: Jon Skeet <jonskeet@google.com>

* respond to feedback.

* Remove ';' from grammar for method_body.

That should not have been included.

* replace "statement body" with "block body".

I'd reversed the committee's decision in the previous commit

* Replace "statement body" with "block body"

* Update standard/classes.md

Co-authored-by: Jon Skeet <jonskeet@google.com>

* "shall not" phrasing

* add empty statement to grammar

Co-authored-by: Rex Jaeschke <rex@RexJaeschke.com>
Co-authored-by: Jon Skeet <jonskeet@google.com>
  • Loading branch information
3 people authored May 13, 2021
1 parent a977b20 commit 4216150
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 26 deletions.
73 changes: 49 additions & 24 deletions standard/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1614,8 +1614,11 @@ member_name
method_body
: block
| '=>' expression ';'
| ';'
;
```
A *method_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and a valid combination of the four access modifiers ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `static` ([§15.6.3](classes.md#1563-static-and-instance-methods)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods)), `override` ([§15.6.5](classes.md#1565-override-methods)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods)), `extern` ([§15.6.8](classes.md#1568-external-methods)) and `async` ([§15.15](classes.md#1515-async-functions)) modifiers.

A declaration has a valid combination of modifiers if all of the following are true:
Expand All @@ -1637,7 +1640,9 @@ The optional *formal_parameter_list* specifies the parameters of the method ([§

The *return_type* and each of the types referenced in the *formal_parameter_list* of a method shall be at least as accessible as the method itself ([§8.5.5](basic-concepts.md#855-accessibility-constraints)).

For abstract and extern methods, the *method_body* consists simply of a semicolon. For partial methods the *method_body* may consist of either a semicolon or a *block*. For all other methods, the *method_body* consists of a *block,* which specifies the statements to execute when the method is invoked.
The *method_body* is either a semicolon, a ***block body*** or an ***expression body***. A block body consists of a *block*, which specifies the statements to execute when the method is invoked. An expression body consists of `=>` followed by an *expression* and a semicolon, and denotes a single expression to perform when the method is invoked.

For abstract and extern methods, the *method_body* consists simply of a semicolon. For partial methods the *method_body* may consist of either a semicolon, a block body or an expression body. For all other methods, the *method_body* is either a block body or an expression body.

If the *method_body* consists of a semicolon, the declaration shall not include the `async` modifier.

Expand Down Expand Up @@ -2492,15 +2497,19 @@ An extension method is a regular static method. In addition, where its enclosing
### 15.6.11 Method body
The *method_body* of a method declaration consists of either a *block* or a semicolon.
The *method_body* of a method declaration consists of either a block body, an expression body or a semicolon.
Abstract and external method declarations do not provide a method implementation, so their method bodies simply consist of a semicolon. For any other method, the method body is a block ([§13.3](statements.md#133-blocks)) that contains the statements to execute when that method is invoked.
The ***effective return type*** of a method is `void` if the return type is `void`, or if the method is async and the return type is `System.Threading.Tasks.Task`. Otherwise, the effective return type of a non-async method is its return type, and the effective return type of an async method with return type `System.Threading.Tasks.Task<T>` is `T`.
When the effective return type of a method is `void`, `return` statements ([§13.10.5](statements.md#13105-the-return-statement)) in that method's body are not permitted to specify an expression. If execution of the method body of a void method completes normally (that is, control flows off the end of the method body), that method simply returns to its caller.
When the effective return type of a method is `void` and the method has a block body, `return` statements ([§13.10.5](statements.md#13105-the-return-statement)) in the block shall not specify an expression. If execution of the block of a void method completes normally (that is, control flows off the end of the method body), that method simply returns to its caller.
When the effective return type of a method is not `void`, each return statement in that method's body shall specify an expression that is implicitly convertible to the effective return type. The endpoint of the method body of a value-returning method shall not be reachable. In other words, in a value-returning method, control is not permitted to flow off the end of the method body.
When a method has a `void` result and an expression body, the expression `E` shall be a *statement_expression*, and the body is exactly equivalent to a statment body of the form `{ E; }`.
When the effective return type of a method is not `void` and the method has a block body, each return statement in that method's body shall specify an expression that is implicitly convertible to the effective return type. The endpoint of the method body of a value-returning method shall not be reachable. In other words, in a value-returning method with a block body, control is not permitted to flow off the end of the method body.
When the effective return type of a method is not `void` and the method has an expression body, `E`, the expression shall be implicitly convertible to the effective return type, and the body is exactly equivalent to a block body of the form `{ return E; }`.
> *Example*: In the following code
> ```csharp
Expand All @@ -2515,12 +2524,13 @@ When the effective return type of a method is not `void`, each return statement
> return 1;
> }
> else {
> return 0;
> return 0;
> }
> }
> public int I(bool b) => b ? 1 : 0;
> }
> ```
> the value-returning `Fmethod results in a compile-time error because control can flow off the end of the method body. The `G` and `Hmethods are correct because all possible execution paths end in a return statement that specifies a return value. *end example*
> the value-returning `Fmethod results in a compile-time error because control can flow off the end of the method body. The `G` and `Hmethods are correct because all possible execution paths end in a return statement that specifies a return value. The `I` method is correct, because its body is equivalent to a statement block with just a single return statement in it. *end example*]
## 15.7 Properties
Expand All @@ -2532,13 +2542,8 @@ Properties are declared using *property_declaration*s:
```ANTLR
property_declaration
: attributes? property_modifiers? type member_name '{' accessor_declarations '}'
;
property_modifiers
: property_modifier
| property_modifiers property_modifier
;
: attributes? property_modifier* type member_name property_body
;
property_modifier
: 'new'
Expand All @@ -2553,6 +2558,15 @@ property_modifier
| 'abstract'
| 'extern'
;
property_body
: '{' accessor_declarations '}' property_initializer?
| '=>' expression ';'
;
property_initializer
: '=' variable_initializer ';'
;
```
A *property_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and a valid combination of the four access modifiers ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `static` ([§15.7.2](classes.md#1572-static-and-instance-properties)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods), [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors)), `override` ([§15.6.5](classes.md#1565-override-methods), [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods), [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors)), and `extern` ([§15.6.8](classes.md#1568-external-methods)) modifiers.
Expand All @@ -2563,7 +2577,11 @@ The *type* of a property declaration specifies the type of the property introduc

The *type* of a property shall be at least as accessible as the property itself ([§8.5.5](basic-concepts.md#855-accessibility-constraints)).

The *accessor_declarations*, which shall be enclosed in "`{`" and "`}`" tokens, declare the accessors ([§15.7.3](classes.md#1573-accessors)) of the property. The accessors specify the executable statements associated with reading and writing the property.
A *property_body* may either consist of an ***accessor body*** or an expression body ([§15.6.1](classes.md#1561-general)). In an accessor body, *accessor_declarations*, which shall be enclosed in "`{`" and "`}`" tokens, declare the accessors ([§15.7.3](classes.md#1573-accessors)) of the property. The accessors specify the executable statements associated with reading and writing the property.

An expression body consisting of `=>` followed by an *expression* `E` and a semicolon is exactly equivalent to the block body `{ get { return E; } }`, and can therefore only be used to specify getter-only properties where the result of the getter is given by a single expression.

A *property_initializer* may only be given for an automatically implemented property ([§xxx](classes.md#automatically-implemented-properties)), and causes the initialization of the underlying field of such properties with the value given by the *expression*.

Even though the syntax for accessing a property is the same as that for a field, a property is not classified as a variable. Thus, it is not possible to pass a property as a `ref` or `out` argument.

Expand Down Expand Up @@ -3233,13 +3251,8 @@ An ***indexer*** is a member that enables an object to be indexed in the same wa
```ANTLR
indexer_declaration
: attributes? indexer_modifiers? indexer_declarator '{' accessor_declarations '}'
;
indexer_modifiers
: indexer_modifier
| indexer_modifiers indexer_modifier
;
: attributes? indexer_modifier* indexer_declarator indexer_body
;
indexer_modifier
: 'new'
Expand All @@ -3258,6 +3271,11 @@ indexer_declarator
: type 'this' '[' formal_parameter_list ']'
| type interface_type '.' 'this' '[' formal_parameter_list ']'
;
indexer_body
: '{' accessor_declarations '}'
| '=>' expression ';'
;
```
An *indexer_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and a valid combination of the four access modifiers ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods)), `override` ([§15.6.5](classes.md#1565-override-methods)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods)), and `extern` ([§15.6.8](classes.md#1568-external-methods)) modifiers.
Expand All @@ -3276,7 +3294,9 @@ The *formal_parameter_list* specifies the parameters of the indexer. The formal

The *type* of an indexer and each of the types referenced in the *formal_parameter_list* shall be at least as accessible as the indexer itself ([§8.5.5](basic-concepts.md#855-accessibility-constraints)).

The *accessor_declarations* ([§15.7.3](classes.md#1573-accessors)), which shall be enclosed in "`{`" and "`}`" tokens, declare the accessors of the indexer. The accessors specify the executable statements associated with reading and writing indexer elements.
An *indexer_body* may either consist of an accessor body ([§15.7.1](classes.md#1571-general)) or an expression body ([§15.6.1](classes.md#1561-general)). In an accessor body, *accessor_declarations*, which shall be enclosed in "`{`" and "`}`" tokens, declare the accessors ([§15.7.3](classes.md#1573-accessors)) of the indexer. The accessors specify the executable statements associated with reading and writing indexer elements.

An expression body consisting of "`=>`" followed by an expression `E` and a semicolon is exactly equivalent to the block body `{ get { return E; } }`, and can therefore only be used to specify getter-only indexers where the result of the getter is given by a single expression.

Even though the syntax for accessing an indexer element is the same as that for an array element, an indexer element is not classified as a variable. Thus, it is not possible to pass an indexer element as a `ref` or `out` argument.

Expand All @@ -3293,8 +3313,9 @@ Indexers and properties are very similar in concept, but differ in the following
- A `set` accessor of a property corresponds to a method with a single parameter named value, whereas a `set` accessor of an indexer corresponds to a method with the same formal parameter list as the indexer, plus an additional parameter named value.
- It is a compile-time error for an indexer accessor to declare a local variable or local constant with the same name as an indexer parameter.
- In an overriding property declaration, the inherited property is accessed using the syntax `base.P`, where `P` is the property name. In an overriding indexer declaration, the inherited indexer is accessed using the syntax `base[E]`, where `E` is a comma-separated list of expressions.
- There is no concept of an "automatically implemented indexer". It is an error to have a non-abstract, non-external indexer with semicolon accessors.

Aside from these differences, all rules defined in [§15.7.3](classes.md#1573-accessors) and [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors) apply to indexer accessors as well as to property accessors.
Aside from these differences, all rules defined in [§15.7.3](classes.md#1573-accessors) and [§xxx](classes.md#automatically-implemented-properties) apply to indexer accessors as well as to property accessors.

When an indexer declaration includes an `extern` modifier, the indexer is said to be an ***external indexer***. Because an external indexer declaration provides no actual implementation, each of its *accessor_declarations* consists of a semicolon.

Expand Down Expand Up @@ -3443,13 +3464,17 @@ conversion_operator_declarator
operator_body
: block
| '=>' expression ';'
| ';'
;
```
There are three categories of overloadable operators: Unary operators ([§15.10.2](classes.md#15102-unary-operators)), binary operators ([§15.10.3](classes.md#15103-binary-operators)), and conversion operators ([§15.10.4](classes.md#15104-conversion-operators)).

When an operator declaration includes an `extern` modifier, the operator is said to be an ***external operator***. Because an external operator provides no actual implementation, its *operator_body* consists of a semi-colon. For all other operators, the *operator_body* consists of a *block*, which specifies the statements to execute when the operator is invoked. The *block* of an operator shall conform to the rules for value-returning methods described in [§15.6.11](classes.md#15611-method-body).
The *operator_body* is either a semicolon, a block body ([§15.6.1](classes.md#1561-general)) or an expression body ([§15.6.1](classes.md#1561-general)). A block body consists of a *block*, which specifies the statements to execute when the operator is invoked. The *block* shall conform to the rules for value-returning methods described in [§15.6.11](classes.md#15611-method-body). An expression body consists of `=>` followed by an expression and a semicolon, and denotes a single expression to perform when the operator is invoked.

For `extern` operators, the *operator_body* consists simply of a semicolon. For all other operators, the *operator_body* is either a block body or an expression body.

The following rules apply to all operator declarations:

Expand Down
4 changes: 2 additions & 2 deletions standard/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4109,9 +4109,9 @@ A *block* body of an anonymous function is always reachable ([§13.2](statements
> *Example*: Some examples of anonymous functions follow below:
> ```csharp
> x => x + 1 // Implicitly typed, expression body
> x => { return x + 1; } // Implicitly typed, statement body
> x => { return x + 1; } // Implicitly typed, block body
> (int x) => x + 1 // Explicitly typed, expression body
> (int x) => { return x + 1; } // Explicitly typed, statement body
> (int x) => { return x + 1; } // Explicitly typed, block body
> (x, y) => x * y // Multiple parameters
> () => Console.WriteLine() // No parameters
> async (t1,t2) => await t1 + await t2 // Async
Expand Down

0 comments on commit 4216150

Please sign in to comment.