You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: proposals/csharp-7.0/tuples.md
+32-52Lines changed: 32 additions & 52 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -68,7 +68,7 @@ tuple_type_element
68
68
69
69
### Tuple types
70
70
71
-
Tuple types are declared with a syntax very similar to a parameter list:
71
+
Tuple types are declared with the following syntax:
72
72
73
73
```csharp
74
74
public (intsum, intcount) Tally(IEnumerable<int> values) { ... }
@@ -157,18 +157,18 @@ byte y;
157
157
158
158
The evaluation order of deconstruction assignment expressions is "breadth first":
159
159
160
-
1.**Evaluate the LHS**. That means evaluate each of the expressions inside of it one by one, left to right, to yield side effects and establish a storage location for each.
161
-
1.**Evaluate the RHS**. That means evaluate each of the expressions inside of it one by one, left to right to yield side effects
160
+
1. Evaluate the LHS: Evaluate each of the expressions inside of it one by one, left to right, to yield side effects and establish a storage location for each.
161
+
1. Evaluate the RHS: Evaluate each of the expressions inside of it one by one, left to right to yield side effects
162
162
1. Convert each of the RHS expressions to the LHS types expected, one by one, left to right.
163
-
1. Assign each of the conversion results from 3 to the storage locations found in 1.
163
+
1. Assign each of the conversion results from 3 to the storage locations found in
164
164
165
165
> **Note to reviewers**: I found this in the LDM notes for July 13-16, 2016. I don't think it is still accurate:
166
166
167
167
A deconstructing assignment is a *statement-expression* whose type could be `void`.
168
168
169
169
### Duality with underlying type
170
170
171
-
Tuples map to underlying types of particular names -
171
+
Tuples map to underlying types of particular names.
vart2= (misc: 0, Item1: 1); // error: "Item1" was used in a wrong position
203
203
```
204
204
205
-
If the tuple is bigger than the limit of 7, the implementation will nest the "tail" as a tuple into the eighth element recursively. This nesting is visible by accessing the `Rest` field of a tuple, but that field is considered an implementation detail, and is hidden from e.g. auto-completion, just as the `ItemX` field names are hidden but allowed when a tuple has named elements.
205
+
If the tuple is bigger than the limit of 7, the implementation will nest the "tail" as a tuple into the eighth element recursively. This nesting is visible by accessing the `Rest` field of a tuple, but that field my be hidden from e.g. auto-completion, just as the `ItemX` field names may be hidden but allowed when a tuple has named elements.
206
206
207
207
A well formed "big tuple" will have names `Item1` etc. all the way up to the number of tuple elements, even though the underlying type doesn't physically have those fields directly defined. The same goes for the tuple returned from the `Rest` field, only with the numbers "shifted" appropriately.
208
208
@@ -215,11 +215,11 @@ partial class C : IEnumerable<(string fullname, int)> { ... } // error: names mu
215
215
216
216
When tuple elements names are used in overridden signatures, or implementations of interface methods, tuple element names in parameter and return types must be preserved. It is an error for the same generic interface to be inherited or implemented twice with identity convertible type arguments that have conflicting tuple element names
217
217
218
-
### Overloading, overriding, hiding
219
-
220
-
For the purpose of overloading, overriding and hiding, tuples of the same types and lengths as well as their underlying ValueTuple types are considered equivalent. All other differences are immaterial. When overriding a member it is permitted to use tuple types with same or different field names than in the base member.
221
-
222
-
A situation where same field names are used for non-matching fields between base and derived member signatures, a warning is reported by the compiler.
218
+
> note:
219
+
>
220
+
> For the purpose of overloading, overriding and hiding, tuples of the same types and lengths as well as their underlying ValueTuple types are considered equivalent. All other differences are immaterial. When overriding a member it is permitted to use tuple types with same or different field names than in the base member.
221
+
>
222
+
> A situation where same field names are used for non-matching fields between base and derived member signatures, a warning is reported by the compiler.
223
223
224
224
```csharp
225
225
classBase
@@ -243,6 +243,8 @@ class InvalidOverloading
243
243
}
244
244
```
245
245
246
+
> endnote.
247
+
246
248
### Tuple field name erasure at runtime
247
249
248
250
Tuple field names aren't part of the runtime representation of tuples, but are tracked only by the compiler. As a result, the field names will not be available to a 3rd party observer of a tuple instance - such as reflection or dynamic code.
That said, if you have an element name at one position on one side of a conversion, and the same name at another position on the other side, you almost certainly have bug in your code:
294
+
> note:
295
+
>
296
+
> An element name at one position on one side of a conversion, and the same name at another position on the other side almost certainly have bug in the code:
Compilers should issue a warning for the preceding code.
303
+
> Compilers should issue a warning for the preceding code.
304
+
>
305
+
> endnote.
300
306
301
307
### Boxing conversions
302
308
303
309
> The following text should be added to [Boxing conversions](../../spec/conversions.md#boxing-conversions) after the first paragraph:
304
310
305
-
As a *value_type*, tuples naturally have a boxing conversion. Importantly, the names aren't part of the runtime representation of tuples, but are tracked only by the compiler. Thus, once you've "cast away" the names, you cannot recover them. In alignment with the identity conversions, a boxed tuple will unbox to any tuple type that has the same element types in the same order.
311
+
Tuples, like all value types, have a boxing conversion. Importantly, the names aren't part of the runtime representation of tuples, but are tracked only by the compiler. Thus, once you've "cast away" the names, you cannot recover them. In alignment with the identity conversions, a boxed tuple will unbox to any tuple type that has the same element types in the same order.
306
312
307
313
### Tuple conversions
308
314
@@ -313,20 +319,13 @@ For the classification purpose, all element conversions are considered recursive
313
319
314
320
Tuple conversions are *Standard Conversions* and therefore can stack with user-defined operators to form user-defined conversions.
315
321
316
-
A tuple conversion can be classified as a valid instance conversion for an extension method invocation as long as all element conversions are applicable as instance conversions.
317
-
318
-
On top of the member-wise conversions implied by target typing, we can certainly allow implicit conversions between tuple types themselves.
319
-
320
-
Specifically, covariance seems straightforward, because the tuples are value types: As long as each member of the assigned tuple is assignable to the type of the corresponding member of the receiving tuple, things should be good.
321
-
322
322
An implicit tuple conversion is a standard conversion. It applies between two tuple types of equal arity when there is any implicit conversion between each corresponding pair of types.
323
323
324
324
An explicit tuple conversion is a standard conversion. It applies between two tuple types of equal arity when there is any explicit conversion between each corresponding pair of types.
A tuple conversion can be classified as a valid instance conversion or an extension method invocation as long as all element conversions are applicable as instance conversions.
327
+
328
+
On top of the member-wise conversions implied by target typing, implicit conversions between tuple types themselves are allowed.
330
329
331
330
### Target typing
332
331
@@ -338,25 +337,7 @@ A tuple literal is "target typed" when used in a context specifying a tuple type
338
337
(stringname, byteage) t= (null, 5); // Ok: the expressions null and 5 convert to string and byte
339
338
```
340
339
341
-
In cases where the tuple literal is not part of a conversion, a tuple is used by its "natural type", which means a tuple type where the element types are the types of the constituent expressions. Since not all expressions have types, not all tuple literals have a natural type either:
342
-
343
-
```csharp
344
-
vart= ("John", 5); // Ok: the type of t is (string, int)
345
-
vart= (null, 5); // Error: tuple expression doesn't have a type because null does not have a type
346
-
((1,2, null), 5).ToString(); // Error: tuple expression doesn't have a type
347
-
348
-
ImmutableArray.Create((()=>1, 1)); // Error: tuple expression doesn't have a type because lambda does not have a type
349
-
ImmutableArray.Create(((Func<int>)(()=>1), 1)); // ok
350
-
```
351
-
352
-
A tuple literal may include names, in which case they become part of the natural type:
353
-
354
-
```csharp
355
-
vart= (name: "John", age: 5); // The type of t is (string name, int age)
356
-
t.age++; // t has field named age.
357
-
```
358
-
359
-
A successful conversion from tuple expression to tuple type is classified as an *ImplicitTuple* conversion, unless tuple's natural type matches the target type exactly, in such case it is an *Identity* conversion.
340
+
A successful conversion from tuple expression to tuple type is classified as an *ImplicitTuple* conversion, unless the tuple's natural type matches the target type exactly, in such case it is an *Identity* conversion.
360
341
361
342
```csharp
362
343
voidM1((intx, inty) arg){...};
@@ -401,8 +382,6 @@ The `_` wildcard indicates that the one or more of the tuple fields are discarde
401
382
Console.WriteLine($"Sum: {sum}, count was ignored");
402
383
```
403
384
404
-
> Note: Should the `_` be added as a token? How was that resolved?
405
-
406
385
Any object may be deconstructed by providing an accessible `Deconstruct` method, either as a member or as an extension method. A `Deconstruct` method converts an object to a set of discrete values. The Deconstruct method "returns" the component values by use of individual `out` parameters. Deconstruct is overloadable.
407
386
408
387
The deconstructor pattern could be implemented as a member method, or an extension method:
@@ -445,13 +424,14 @@ p.Deconstruct(out byte __x, out byte __y);
445
424
446
425
> The following note should be added to the end of the section on [extension methods](../../spec/classes.md#extension-methods):
447
426
448
-
Note: Extension methods
449
-
450
-
on a tuple type apply to tuples with different element names:
427
+
> note:
428
+
>Extension methods on a tuple type apply to tuples with different element names:
0 commit comments