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# 7.x: Default literals #236

Merged
merged 11 commits into from
Nov 30, 2022
5 changes: 5 additions & 0 deletions standard/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ The following conversions are classified as implicit conversions:
- Null literal conversions
- Implicit nullable conversions
- Lifted user-defined implicit conversions
- Default literal conversions
- Implicit throw conversion

Implicit conversions can occur in a variety of situations, including function member invocations ([§11.6.6](expressions.md#1166-function-member-invocation)), cast expressions ([§11.8.7](expressions.md#1187-cast-expressions)), and assignments ([§11.19](expressions.md#1119-assignment-operators)).
Expand Down Expand Up @@ -302,6 +303,10 @@ A user-defined implicit conversion consists of an optional standard implicit con

Anonymous functions and method groups do not have types in and of themselves, but they may be implicitly converted to delegate types. Additionally, some lambda expressions may be implicitly converted to expression tree types. Anonymous function conversions are described in more detail in [§10.7](conversions.md#107-anonymous-function-conversions) and method group conversions in [§10.8](conversions.md#108-method-group-conversions).

### §default-literal-new-clause Default literal conversions

An implicit conversion exists from a *default_literal* ([§11.7.19](expressions.md#11719-default-value-expressions)) to any type. This conversion produces the default value ([§9.3](variables.md#93-default-values)) of the inferred type.

### 10.2.15 Implicit throw conversions

While throw expressions do not have a type, they may be implicitly converted to any type.
Expand Down
22 changes: 18 additions & 4 deletions standard/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2819,17 +2819,28 @@ The `unchecked` operator is convenient when writing constants of the signed inte

### 11.7.19 Default value expressions

A default value expression is used to obtain the default value ([§9.3](variables.md#93-default-values)) of a type. Typically a default value expression is used for type parameters, since it might not be known if the type parameter is a value type or a reference type. (No conversion exists from the `null` literal ([§6.4.5.7](lexical-structure.md#6457-the-null-literal)) to a type parameter unless the type parameter is known to be a reference type ([§8.2](types.md#82-reference-types)).)
A default value expression is used to obtain the default value ([§9.3](variables.md#93-default-values)) of a type.

```ANTLR
default_value_expression
: explictly_typed_default
| default_literal
;

explictly_typed_default
: 'default' '(' type ')'
;

default_literal
: 'default'
;
```

If the *type* in a *default_value_expression* evaluates at run-time to a reference type, the result is `null` converted to that type. If the *type* in a *default_value_expression* evaluates at run-time to a value type, the result is the value type’s default value ([§8.3.3](types.md#833-default-constructors)).
A *default_literal* represents a default value (§9.3). It does not have a type, but can be converted to any type through a default literal conversion (§default-literal-new-clause).
jskeet marked this conversation as resolved.
Show resolved Hide resolved

The result of a *default_value_expression* is the default ([§9.3](variables.md#93-default-values)) of the explicit type in an *explictly_typed_default*, or the target type of the conversion for a *default_value_expression*.

A *default_value_expression* is a constant expression ([§11.21](expressions.md#1121-constant-expressions)) if *type* is a reference type or a type parameter that is known to be a reference type ([§8.2](types.md#82-reference-types)). In addition, a *default_value_expression* is a constant expression if the type is one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,` or any enumeration type.
A *default_value_expression* is a constant expression ([§11.21](expressions.md#1121-constant-expressions)) if explicit or inferred *type* is a reference type or a type parameter that is known to be a reference type ([§8.2](types.md#82-reference-types)). In addition, a *default_value_expression* is a constant expression if the type is one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool,` or any enumeration type.
jskeet marked this conversation as resolved.
Show resolved Hide resolved
jskeet marked this conversation as resolved.
Show resolved Hide resolved

### 11.7.20 Nameof expressions

Expand Down Expand Up @@ -3640,6 +3651,9 @@ The `is` operator is described in [§11.11.11](expressions.md#111111-the-is-oper

The `==`, `!=`, `<`, `>`, `<=` and `>=` operators are ***comparison operators***.

If a *default_literal* ([§11.7.19](expressions.md#11719-default-value-expressions)) is used as an operand of a `<`, `>`, `<=`, or `>=` operator, a compile-time error occurs.
If a *default_literal* is used as both operands of a `==` or `!=` operator, a compile-time error occurs. If a *default_literal* is used as the left operand of the `is` or `as` operator, a compile-time error occurs.

If an operand of a comparison operator has the compile-time type `dynamic`, then the expression is dynamically bound ([§11.3.3](expressions.md#1133-dynamic-binding)). In this case the compile-time type of the expression is `dynamic`, and the resolution described below will take place at run-time using the run-time type of those operands that have the compile-time type `dynamic`.

For an operation of the form `x «op» y`, where «op» is a comparison operator, overload resolution ([§11.4.5](expressions.md#1145-binary-operator-overload-resolution)) is applied to select a specific operator implementation. The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. If both operands of an *equality_expression* are the `null` literal, then overload resolution is not performed and the expression evaluates to a constant value of `true` or `false` according to whether the operator is `==` or `!=`.
Expand Down Expand Up @@ -4278,7 +4292,7 @@ The conditional operator is right-associative, meaning that operations are group

The first operand of the `?:` operator shall be an expression that can be implicitly converted to `bool`, or an expression of a type that implements `operator true`. If neither of these requirements is satisfied, a compile-time error occurs.

The second and third operands, `x` and `y`, of the `?:` operator control the type of the conditional expression.
The second and third operands, `x` and `y`, of the `?:` operator control the type of the conditional expression. If both `x` and `y` are *default_literal*s ([§11.7.19](expressions.md#11719-default-value-expressions)), a compile-time error occurs.

- If `x` has type `X` and `y` has type `Y` then,
- If `X` and `Y` are the same type, then this is the type of the conditional expression.
Expand Down
1 change: 1 addition & 0 deletions standard/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ The default value of a variable depends on the type of the variable and is deter

- For a variable of a *value_type*, the default value is the same as the value computed by the *value_type*’s default constructor ([§8.3.3](types.md#833-default-constructors)).
- For a variable of a *reference_type*, the default value is `null`.
- In an unsafe context, for a variable of a *pointer_type*, the default value is `null`.
jskeet marked this conversation as resolved.
Show resolved Hide resolved

> *Note*: Initialization to default values is typically done by having the memory manager or garbage collector initialize memory to all-bits-zero before it is allocated for use. For this reason, it is convenient to use all-bits-zero to represent the null reference. *end note*

Expand Down