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

Discards, tuples and out variables #664

Merged
merged 45 commits into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
b51c0cf
Rough cut at discards, tuples and out variables
MadsTorgersen Nov 2, 2022
0e9bcda
Fix typos
MadsTorgersen Nov 2, 2022
c6a30bc
Fix indentation and whitespace
MadsTorgersen Nov 2, 2022
4bea703
Fix up tuples
MadsTorgersen Nov 2, 2022
c9152a7
Fix section and word converter errors
MadsTorgersen Nov 2, 2022
7908b94
Fix typos and lint errors
MadsTorgersen Nov 2, 2022
97bfb5c
Merge branch 'draft-v7' into Mads-v7-local-declarations-in-expressions
MadsTorgersen Nov 22, 2022
fc50f9c
Crisp up deconstruction
MadsTorgersen Nov 30, 2022
7b553a0
Merge branch 'draft-v7' into Mads-v7-local-declarations-in-expressions
MadsTorgersen Jan 27, 2023
5b1c905
Apply suggestions from code review
MadsTorgersen Jan 27, 2023
05821a9
Add examples and section references, fix issues from review comments
MadsTorgersen Jan 27, 2023
cb6ce12
Merge branch 'Mads-v7-local-declarations-in-expressions' of https://g…
MadsTorgersen Jan 27, 2023
f67f61d
Fix lint issues
MadsTorgersen Jan 27, 2023
7114566
Add examples
MadsTorgersen Jan 28, 2023
4d75674
Update variables.md
MadsTorgersen Jan 28, 2023
2048881
Add examples
MadsTorgersen Jan 31, 2023
7896208
Fix editorial comments
MadsTorgersen Jan 31, 2023
eeec248
Fix declaration spaces and simple name lookup
MadsTorgersen Feb 1, 2023
231a77e
Update basic-concepts.md
MadsTorgersen Feb 1, 2023
25d39d0
Fix local declarations
MadsTorgersen Feb 1, 2023
0fb99c1
Update statements.md
MadsTorgersen Feb 1, 2023
26d24a3
Fix deconstructing assignment
MadsTorgersen Feb 9, 2023
1107b68
Fix linting issues
MadsTorgersen Feb 9, 2023
d180df7
Fix more linting issues
MadsTorgersen Feb 9, 2023
39a3c1a
Fix issues from comments
MadsTorgersen Feb 10, 2023
02b0dc7
Try to fix linting issue
MadsTorgersen Feb 10, 2023
2b67781
Fix linting issue
MadsTorgersen Feb 10, 2023
3231f81
Fix several comments from gafter
MadsTorgersen Mar 20, 2023
eb94c3f
Fix "projection" tuple element names
MadsTorgersen Mar 20, 2023
97379cb
Fix overload resolution with out vars
MadsTorgersen Mar 20, 2023
d48514a
Fix declaration expressions and overload resolution
MadsTorgersen Mar 21, 2023
8737fc4
Root declaration_expression
MadsTorgersen Mar 21, 2023
5f62fd2
Add tuple equality
MadsTorgersen Mar 22, 2023
218921f
Fixing linter errors
MadsTorgersen Mar 22, 2023
205760f
Add deconstruction expressions
MadsTorgersen Mar 22, 2023
978b3dc
Fix lint errors
MadsTorgersen Mar 22, 2023
c36dc0b
Fix wording
MadsTorgersen Mar 22, 2023
f4cfcc8
Root tuple_expression
MadsTorgersen Mar 22, 2023
1316315
Add definite assignment rules for new expression forms
MadsTorgersen Mar 22, 2023
797c301
Fix lint errors
MadsTorgersen Mar 22, 2023
938205b
wordsmith
MadsTorgersen Mar 22, 2023
8e94899
Unify deconstruction expressions with tuple expresseions
MadsTorgersen Mar 22, 2023
40127a2
Merge branch 'Mads-v7-local-declarations-in-expressions' of https://g…
MadsTorgersen Mar 22, 2023
b0de44f
Add note about discards as out arguments
MadsTorgersen Apr 6, 2023
5bfcb45
Remove space
MadsTorgersen Apr 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions standard/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,16 @@ There are several different types of declaration spaces, as described in the fol
- Within all compilation units of a program, *namespace_member_declaration*s with no enclosing *namespace_declaration* are members of a single combined declaration space called the ***global declaration space***.
- Within all compilation units of a program, *namespace_member_declaration*s within *namespace_declaration*s that have the same fully qualified namespace name are members of a single combined declaration space.
- Each *compilation_unit* and *namespace_body* has an ***alias declaration space***. Each *extern_alias_directive* and *using_alias_directive* of the *compilation_unit* or *namespace_body* contributes a member to the alias declaration space ([§13.5.2](namespaces.md#1352-using-alias-directives)).
- Each non-partial class, struct, or interface declaration creates a new declaration space. Each partial class, struct, or interface declaration contributes to a declaration space shared by all matching parts in the same program ([§15.2.3](structs.md#1523-partial-modifier)).Names are introduced into this declaration space through *class_member_declaration*s, *struct_member_declaration*s, *interface_member_declaration*s, or *type_parameter*s. Except for overloaded instance constructor declarations and static constructor declarations, a class or struct cannot contain a member declaration with the same name as the class or struct. A class, struct, or interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)). Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. Such a member is said to ***hide*** the inherited member.
- Each non-partial class, struct, or interface declaration creates a new declaration space. Each partial class, struct, or interface declaration contributes to a declaration space shared by all matching parts in the same program ([§15.2.3](structs.md#1523-partial-modifier)). Names are introduced into this declaration space through *class_member_declaration*s, *struct_member_declaration*s, *interface_member_declaration*s, or *type_parameter*s. Except for overloaded instance constructor declarations and static constructor declarations, a class or struct cannot contain a member declaration with the same name as the class or struct. A class, struct, or interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)). Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. Such a member is said to ***hide*** the inherited member.
MadsTorgersen marked this conversation as resolved.
Show resolved Hide resolved
- Each delegate declaration creates a new declaration space. Names are introduced into this declaration space through formal parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s.
- Each enumeration declaration creates a new declaration space. Names are introduced into this declaration space through *enum_member_declarations*.
- Each method declaration, property declaration, property accessor declaration, indexer declaration, indexer accessor declaration, operator declaration, instance constructor declaration, anonymous function, and local function creates a new declaration space called a ***local variable declaration space***. Names are introduced into this declaration space through formal parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s. The set accessor for a property or an indexer introduces the name `value` as a formal parameter. The body of the function member, anonymous function, or local function, if any, is considered to be nested within the local variable declaration space. It is an error for a local variable declaration space and a nested local variable declaration space to contain elements with the same name. Thus, within a nested declaration space it is not possible to declare a local variable or constant with the same name as a local variable or constant in an enclosing declaration space. It is possible for two declaration spaces to contain elements with the same name as long as neither declaration space contains the other.
- Each *block* or *switch_block*, as well as a `for`, `foreach`, and `using` statement, creates a local variable declaration space for local variables and local constants. Names are introduced into this declaration space through *local_variable_declaration*s and *local_constant_declaration*s. Note that blocks that occur as or within the body of a function member, anonymous function, or local function are nested within the local variable declaration space declared by those functions for their parameters. Thus, it is an error to have, for example, a method with a local variable and a parameter of the same name.

- Each method declaration, property declaration, property accessor declaration, indexer declaration, indexer accessor declaration, operator declaration, instance constructor declaration, anonymous function, and local function creates a new declaration space called a ***local variable declaration space***. Names are introduced into this declaration space through formal parameters (*fixed_parameter*s and *parameter_array*s) and *type_parameter*s. The set accessor for a property or an indexer introduces the name `value` as a formal parameter.
- Additional local variable declaration spaces may occur within member declarations, anonymous functions and local functions. Names are introduced into these declaration spaces through *declaration_expression*s and *declaration_statement*s. Local variable declaration spaces may be nested, but it is an error for a local variable declaration space and a nested local variable declaration space to contain elements with the same name. Thus, within a nested declaration space it is not possible to declare a local variable or constant with the same name as a parameter, type parameter, local variable or constant in an enclosing declaration space. It is possible for two declaration spaces to contain elements with the same name as long as neither declaration space contains the other. Local declaration spaces are created by the following constructs:
MadsTorgersen marked this conversation as resolved.
Show resolved Hide resolved
MadsTorgersen marked this conversation as resolved.
Show resolved Hide resolved
- Each *variable_initializer* in a field and property declaration introduces its own local variable declaration space, that is not nested within any other local variable declaration space.
- The body of a function member, anonymous function, or local function, if any, creates a local variable declaration space that is considered to be nested within the function's local variable declaration space.
MadsTorgersen marked this conversation as resolved.
Show resolved Hide resolved
- Each *constructor_initializer* creates a local variable declaration space nested within the instance constructor declaration. The local variable declaration space for the constructor body is in turn nested within this local variable declaration space.
- Each *block*, *switch_block*, *iteration_statement* and *using_statement* creates a nested local variable declaration space.
- Each *embedded_statement* that is not directly part of a *statement_list* creates a nested local variable declaration space.
MadsTorgersen marked this conversation as resolved.
Show resolved Hide resolved
- Each *block* or *switch_block* creates a separate declaration space for labels. Names are introduced into this declaration space through *labeled_statement*s, and the names are referenced through *goto_statement*s. The ***label declaration space*** of a block includes any nested blocks. Thus, within a nested block it is not possible to declare a label with the same name as a label in an enclosing block.

The textual order in which names are declared is generally of no significance. In particular, textual order is not significant for the declaration and use of namespaces, constants, methods, properties, events, indexers, operators, instance constructors, finalizers, static constructors, and types. Declaration order is significant in the following ways:
Expand Down
32 changes: 31 additions & 1 deletion standard/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ The following conversions are classified as implicit conversions:
- Method group conversions
- Null literal conversions
- Implicit nullable conversions
- Implicit tuple conversions
- Lifted user-defined implicit conversions
- Default literal conversions
- Implicit throw conversion
Expand All @@ -78,7 +79,11 @@ However, dynamic conversions ([§10.2.10](conversions.md#10210-implicit-dynamic-

An identity conversion converts from any type to the same type. One reason this conversion exists is so that a type T or an expression of type T can be said to be convertible to T itself.

Because `object` and `dynamic` are considered equivalent there is an identity conversion between `object` and `dynamic`, and between constructed types that are the same when replacing all occurrences of `dynamic` with `object`.
In some cases there is an identity conversion between types that are not exactly the same, but are considered equivalent. Such identity conversions exist:
MadsTorgersen marked this conversation as resolved.
Show resolved Hide resolved

- between `object` and `dynamic`.
- between tuple types with the same arity, when an identity conversion exists between each pair of corresponding element types.
- between types constructed from the same generic type where there exists an identity conversion between each corresponding type argument.

In most cases, an identity conversion has no effect at runtime. However, since floating point operations may be performed at higher precision than prescribed by their type ([§8.3.7](types.md#837-floating-point-types)), assignment of their results may result in a loss of precision, and explicit casts are guaranteed to reduce precision to what is prescribed by the type ([§11.8.7](expressions.md#1187-cast-expressions)).

Expand Down Expand Up @@ -310,6 +315,26 @@ The following further implicit conversions exist for a given type parameter `T`

In all cases, the rules ensure that a conversion is executed as a boxing conversion if and only if at run-time the conversion is from a value type to a reference type.

### §implicit-tuple-conversions-new-clause Implicit tuple conversions

An implicit conversion exists from a tuple expression `E` to a tuple type `T` if `E` has the same arity as `T` and an implicit conversion exists from each element in `E` to the corresponding element type in `T`. The conversion is performed by creating an instance of `T`'s corresponding `System.ValueTuple<...>` type, and initializing each of its fields in order from left to right by evaluating the corresponding tuple element expression of `E`, converting it to the corresponding element type of `T` using the implicit conversion found, and initializing the field with the result.

If an element name in the tuple expression does not match a corresponding element name in the tuple type, a warning shall be issued.

> *Example*:
>
> ```csharp
> (int, string) t1 = (1, "One");
> (byte, string) t2 = (2, null);
> (int, string) t3 = (null, null); // Error: No conversion
> (int i, string s) t4 = (i: 4, "Four");
> (int i, string) t5 = (x: 5, s: "Five"); // Warning: Names are ignored
> ```
>
> The declarations of `t1`, `t2`, `t4` and `t5` are all valid, since implicit conversions exist from the element expressions to the corresponding element types. The declaration of `t3` is invalid, because there is no conversion from `null` to `int`. The declaration of `t5` causes a warning because the element names in the tuple expression differs from those in the tuple type.
>
> *end example*

### 10.2.13 User-defined implicit conversions

A user-defined implicit conversion consists of an optional standard implicit conversion, followed by execution of a user-defined implicit conversion operator, followed by another optional standard implicit conversion. The exact rules for evaluating user-defined implicit conversions are described in [§10.5.4](conversions.md#1054-user-defined-implicit-conversions).
Expand All @@ -336,6 +361,7 @@ The following conversions are classified as explicit conversions:
- Explicit numeric conversions
- Explicit enumeration conversions
- Explicit nullable conversions
- Explicit tuple conversions
- Explicit reference conversions
- Explicit interface conversions
- Unboxing conversions
Expand Down Expand Up @@ -442,6 +468,10 @@ For an explicit reference conversion to succeed at run-time, the value of the so

> *Note*: Reference conversions, implicit or explicit, never change the value of the reference itself ([§8.2.1](types.md#821-general)), only its type; neither does it change the type or value of the object being referenced. *end note*

### §explicit-tuple-conversions Explicit tuple conversions

An explicit conversion exists from a tuple expression `E` to a tuple type `T` if `E` has the same arity as `T` and an implicit or explicit conversion exists from each element in `E` to the corresponding element type in `T`. The conversion is performed by creating an instance of `T`'s corresponding `System.ValueTuple<...>` type, and initializing each of its fields in order from left to right by evaluating the corresponding tuple element expression of `E`, converting it to the corresponding element type of `T` using the explicit conversion found, and initializing the field with the result.

### 10.3.6 Unboxing conversions

An unboxing conversion permits a *reference_type* to be explicitly converted to a *value_type*. The following unboxing conversions exist:
Expand Down
Loading