diff --git a/standard/basic-concepts.md b/standard/basic-concepts.md index 199b6f978..cfa46bfb9 100644 --- a/standard/basic-concepts.md +++ b/standard/basic-concepts.md @@ -522,9 +522,8 @@ The following accessibility constraints exist: Methods, instance constructors, indexers, and operators are characterized by their ***signatures***: -- The signature of a method consists of the name of the method, the number of type parameters, and the type and parameter-passing mode (value, reference, or output) of each of its formal parameters, considered in the order left to right. For these purposes, any type parameter of the method that occurs in the type of a formal parameter is identified not by its name, but by its ordinal position in the type parameter list of the method. The signature of a method specifically does not include the return type, parameter names, type parameter names, type parameter constraints, the `params` or `this` parameter modifiers, nor whether parameters are required or optional. - -- The signature of an instance constructor consists of the type and parameter-passing mode (value, reference, or output) of each of its formal parameters, considered in the order left to right. The signature of an instance constructor specifically does not include the `params` modifier that may be specified for the right-most parameter. +- The signature of a method consists of the name of the method, the number of type parameters, and the type and parameter-passing mode of each of its formal parameters, considered in the order left to right. For these purposes, any type parameter of the method that occurs in the type of a formal parameter is identified not by its name, but by its ordinal position in the type parameter list of the method. The signature of a method specifically does not include the return type, parameter names, type parameter names, type parameter constraints, the `params` or `this` parameter modifiers, nor whether parameters are required or optional. +- The signature of an instance constructor consists of the type and parameter-passing mode of each of its formal parameters, considered in the order left to right. The signature of an instance constructor specifically does not include the `params` modifier that may be specified for the right-most parameter. - The signature of an indexer consists of the type of each of its formal parameters, considered in the order left to right. The signature of an indexer specifically does not include the element type, nor does it include the `params` modifier that may be specified for the right-most parameter. - The signature of an operator consists of the name of the operator and the type of each of its formal parameters, considered in the order left to right. The signature of an operator specifically does not include the result type. - The signature of a conversion operator consists of the source type and the target type. The implicit or explicit classification of a conversion operator is not part of the signature. @@ -537,9 +536,9 @@ Signatures are the enabling mechanism for ***overloading*** of members in classe - Overloading of indexers permits a class, struct, or interface to declare multiple indexers, provided their signatures are unique within that class, struct, or interface. - Overloading of operators permits a class or struct to declare multiple operators with the same name, provided their signatures are unique within that class or struct. -Although `out` and `ref` parameter modifiers are considered part of a signature, members declared in a single type cannot differ in signature solely by `ref` and `out`. A compile-time error occurs if two members are declared in the same type with signatures that would be the same if all parameters in both methods with `out` modifiers were changed to `ref` modifiers. For other purposes of signature matching (e.g., hiding or overriding), `ref` and `out` are considered part of the signature and do not match each other. +Although `in`, `out`, and `ref` parameter modifiers are considered part of a signature, members declared in a single type cannot differ in signature solely by `in`, `out`, and `ref`. A compile-time error occurs if two members are declared in the same type with signatures that would be the same if all parameters in both methods with `out` or `in` modifiers were changed to `ref` modifiers. For other purposes of signature matching (e.g., hiding or overriding), `in`, `out`, and `ref` are considered part of the signature and do not match each other. -> *Note*: This restriction is to allow C# programs to be easily translated to run on the Common Language Infrastructure (CLI), which does not provide a way to define methods that differ solely in `ref` and `out`. *end note* +> *Note*: This restriction is to allow C# programs to be easily translated to run on the Common Language Infrastructure (CLI), which does not provide a way to define methods that differ solely in `in`, `out`, and `ref`. *end note* The types `object` and `dynamic` are not distinguished when comparing signatures. Therefore members declared in a single type whose signatures differ only by replacing `object` with `dynamic` are not allowed. @@ -567,9 +566,7 @@ The types `object` and `dynamic` are not distinguished when comparing signatures > } > ``` > -> Note that any `ref` and `out` parameter modifiers ([§15.6.2](classes.md#1562-method-parameters)) are part of a signature. Thus, `F(int)`, `F(ref int)`, and `F(out int)` are all unique signatures. However, `F(ref int)` and `F(out int)` cannot be declared within the same interface because their signatures differ solely by `ref` and `out`. Also, note that the return type and the `params` modifier are not part of a signature, so it is not possible to overload solely based on return type or on the inclusion or exclusion of the `params` modifier. As such, the declarations of the methods `F(int)` and `F(params string[])` identified above, result in a compile-time error. -> -> *end example* +> Note that any `in`, `out`, and `ref` parameter modifiers ([§15.6.2](classes.md#1562-method-parameters)) are part of a signature. Thus, `F(int)`, `F(in int)`, `F(out int)` , and `F(ref int)` are all unique signatures. However, `F(in int)`, `F(out int)` , and `F(ref int)` cannot be declared within the same interface because their signatures differ solely by `in`, `out`, and `ref`. Also, note that the return type and the `params` modifier are not part of a signature, so it is not possible to overload solely based on return type or on the inclusion or exclusion of the `params` modifier. As such, the declarations of the methods `F(int)` and `F(params string[])` identified above, result in a compile-time error. *end example* ## 7.7 Scopes diff --git a/standard/classes.md b/standard/classes.md index 0ec0de04d..6ad1f445c 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -776,8 +776,7 @@ A *class_declaration* creates a new declaration space ([§7.3](basic-concepts.md > *Note*: Since the fully qualified name of a type declaration encodes the number of type parameters, two distinct types may share the same name as long as they have different number of type parameters. *end note* - The name of a constant, field, property, or event shall differ from the names of all other members declared in the same class. - -- The name of a method shall differ from the names of all other non-methods declared in the same class. In addition, the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of a method shall differ from the signatures of all other methods declared in the same class, and two methods declared in the same class shall not have signatures that differ solely by `ref` and `out`. +- The name of a method shall differ from the names of all other non-methods declared in the same class. In addition, the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of a method shall differ from the signatures of all other methods declared in the same class, and two methods declared in the same class shall not have signatures that differ solely by `in`, `out`, and `ref`. - The signature of an instance constructor shall differ from the signatures of all other instance constructors declared in the same class, and two constructors declared in the same class shall not have signatures that differ solely by `ref` and `out`. @@ -1989,7 +1988,7 @@ If the *method_body* consists of a semicolon, the declaration shall not include The name, the number of type parameters, and the formal parameter list of a method define the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of the method. Specifically, the signature of a method consists of its name, the number of its type parameters, and the number, *parameter_mode_modifier*s ([§15.6.2.1](classes.md#15621-general)), and types of its formal parameters. The return type is not part of a method’s signature, nor are the names of the formal parameters, the names of the type parameters, or the constraints. When a formal parameter type references a type parameter of the method, the ordinal position of the type parameter (not the name of the type parameter) is used for type equivalence. -The name of a method shall differ from the names of all other non-methods declared in the same class. In addition, the signature of a method shall differ from the signatures of all other methods declared in the same class, and two methods declared in the same class may not have signatures that differ solely by `ref` and `out`. +The name of a method shall differ from the names of all other non-methods declared in the same class. In addition, the signature of a method shall differ from the signatures of all other methods declared in the same class, and two methods declared in the same class may not have signatures that differ solely by `in`, `out`, and `ref`. The method’s *type_parameter*s are in scope throughout the *method_declaration*, and can be used to form types throughout that scope in *return_type*, *method_body*, and *type_parameter_constraints_clause*s but not in *attributes*. @@ -2028,6 +2027,7 @@ parameter_modifier parameter_mode_modifier : 'ref' | 'out' + | 'in' ; parameter_array @@ -2037,9 +2037,9 @@ parameter_array The formal parameter list consists of one or more comma-separated parameters of which only the last may be a *parameter_array*. -A *fixed_parameter* consists of an optional set of *attributes* ([§22](attributes.md#22-attributes)); an optional `ref`, `out`, or `this` modifier; a *type*; an *identifier*; and an optional *default_argument*. Each *fixed_parameter* declares a parameter of the given type with the given name. The `this` modifier designates the method as an extension method and is only allowed on the first parameter of a static method in a non-generic, non-nested static class. Extension methods are further described in [§15.6.10](classes.md#15610-extension-methods). A *fixed_parameter* with a *default_argument* is known as an ***optional parameter***, whereas a *fixed_parameter* without a *default_argument* is a ***required parameter***. A required parameter may not appear after an optional parameter in a *formal_parameter_list*. +A *fixed_parameter* consists of an optional set of *attributes* ([§22](attributes.md#22-attributes)); an optional `in`, `out`, `ref` modifier; a *type*; an *identifier*; and an optional *default_argument*. Each *fixed_parameter* declares a parameter of the given type with the given name. The `this` modifier designates the method as an extension method and is only allowed on the first parameter of a static method in a non-generic, non-nested static class. If the parameter is a `struct` type or a type parameter constrained to a `struct`, the `this` modifier may be combined with either the `ref` or `in` modifier, but not the `out` modifier. Extension methods are further described in [§15.6.10](classes.md#15610-extension-methods). A *fixed_parameter* with a *default_argument* is known as an ***optional parameter***, whereas a *fixed_parameter* without a *default_argument* is a ***required parameter***. A required parameter may not appear after an optional parameter in a *formal_parameter_list*. -A parameter with a `ref`, `out` or `this` modifier cannot have a *default_argument*. The *expression* in a *default_argument* shall be one of the following: +A parameter with a `ref`, `out` or `this` modifier cannot have a *default_argument*. A parameter with an `in` modifier may have a *default_argument*. The *expression* in a *default_argument* shall be one of the following: - a *constant_expression* - an expression of the form `new S()` where `S` is a value type @@ -2077,14 +2077,15 @@ A method declaration creates a separate declaration space ([§7.3](basic-concept A method invocation ([§12.8.9.2](expressions.md#12892-method-invocations)) creates a copy, specific to that invocation, of the formal parameters and local variables of the method, and the argument list of the invocation assigns values or variable references to the newly created formal parameters. Within the *block* of a method, formal parameters can be referenced by their identifiers in *simple_name* expressions ([§12.8.4](expressions.md#1284-simple-names)). -There are four kinds of formal parameters: +The following kinds of formal parameters exist: - Value parameters, which are declared without any modifiers. -- Reference parameters, which are declared with the `ref` modifier. +- Input parameters, which are declared with the `in` modifier. - Output parameters, which are declared with the `out` modifier. +- Reference parameters, which are declared with the `ref` modifier. - Parameter arrays, which are declared with the `params` modifier. -> *Note*: As described in [§7.6](basic-concepts.md#76-signatures-and-overloading), the `ref` and `out` modifiers are part of a method’s signature, but the `params` modifier is not. +> *Note*: As described in [§7.6](basic-concepts.md#76-signatures-and-overloading), the `in`, `out`, and `ref` modifiers are part of a method's signature, but the `params` modifier is not. #### 15.6.2.2 Value parameters @@ -2094,6 +2095,20 @@ When a formal parameter is a value parameter, the corresponding argument in a me A method is permitted to assign new values to a value parameter. Such assignments only affect the local storage location represented by the value parameter—they have no effect on the actual argument given in the method invocation. +#### §method-input-parameters-new-clause Input parameters + +A parameter declared with an `in` modifier is an input parameter. Unlike a value parameter, an input parameter does not create a new storage location. Instead, an input parameter represents the same storage location as the variable given as the argument, or created by the implementation ([§12.6.2.3](expressions.md#12623-run-time-evaluation-of-argument-lists)), in the method invocation. + +When a formal parameter is an input parameter, the corresponding argument in a method invocation shall consist of either the keyword `in` followed by a *variable_reference* (§input-parameters-new-clause) of the same type as the formal parameter, or an *expression* for which an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from that argument expression to the type of the corresponding parameter. A variable shall be definitely assigned before it can be passed as an input parameter. + +It is a compile-time error to modify the value of an input parameter. + +Within a method, an input parameter is always considered definitely assigned. + +A method declared as an iterator ([§15.14](classes.md#1514-iterators)) may not have input parameters. + +In a method that takes input parameters, it is possible for multiple names to represent the same storage location. + #### 15.6.2.3 Reference parameters A parameter declared with a `ref` modifier is a reference parameter. Unlike a value parameter, a reference parameter does not create a new storage location. Instead, a reference parameter represents the same storage location as the variable given as the argument in the method invocation. @@ -2226,7 +2241,7 @@ A parameter declared with a `params` modifier is a parameter array. If a formal > *Example*: The types `string[]` and `string[][]` can be used as the type of a parameter array, but the type `string[,]` can not. *end example* -It is not possible to combine the `params` modifier with the modifiers `ref` and `out`. +It is not possible to combine the `params` modifier with the modifiers `in`, `out`, and `ref`. A parameter array permits arguments to be specified in one of two ways in a method invocation: @@ -2924,7 +2939,11 @@ class Customer ### 15.6.10 Extension methods -When the first parameter of a method includes the `this` modifier, that method is said to be an ***extension method***. Extension methods shall only be declared in non-generic, non-nested static classes. The first parameter of an extension method may have no modifiers other than `this`. +When the first parameter of a method includes the `this` modifier, that method is said to be an ***extension method***. Extension methods shall only be declared in non-generic, non-nested static classes. The first parameter of an extension method is restricted, as follows: + +- It may have the parameter modifier `in` provided the parameter has a value type +- It may have the parameter modifier `ref` provided the parameter has a value type or is a generic type constrained to struct +- It may not be a pointer type. > *Example*: The following is an example of a static class that declares two extension methods: > @@ -3093,7 +3112,7 @@ An expression body consisting of `=>` followed by an *expression* `E` and a semi A *property_initializer* may only be given for an automatically implemented property ([§15.7.4](classes.md#1574-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. +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 an `in`, `out`, or `ref` argument. However, a property can be passed as an *expression* to a method having an input parameter. When a property declaration includes an `extern` modifier, the property is said to be an ***external property***. Because an external property declaration provides no actual implementation, each of its *accessor_declarations* consists of a semicolon. @@ -4046,6 +4065,8 @@ The *type* of an indexer declaration specifies the element type of the indexer i > *Note:* As indexers are designed to be used in array element-like contexts, the term *element type* as defined for an array is also used with an indexer. *end note* +The *formal_parameter_list* specifies the parameters of the indexer. The formal parameter list of an indexer corresponds to that of a method ([§15.6.2](classes.md#1562-method-parameters)), except that at least one parameter shall be specified, and that the `this`, `in`, `out`, and `ref` parameter modifiers are not permitted. + Unless the indexer is an explicit interface member implementation, the *type* is followed by the keyword `this`. For an explicit interface member implementation, the *type* is followed by an *interface_type*, a “`.`”, and the keyword `this`. Unlike other members, indexers do not have user-defined names. The *formal_parameter_list* specifies the parameters of the indexer. The formal parameter list of an indexer corresponds to that of a method ([§15.6.2](classes.md#1562-method-parameters)), except that at least one parameter shall be specified, and that the `this`, `ref`, and `out` parameter modifiers are not permitted. @@ -4062,7 +4083,7 @@ Based on the presence or absence of get and set accessors, an indexer is classif 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 read-only indexers where the result of the get accessor 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. +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 an `in`, `out`, or `ref` argument. The *formal_parameter_list* of an indexer defines the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of the indexer. Specifically, the signature of an indexer consists of the number and types of its formal parameters. The element type and names of the formal parameters are not part of an indexer’s signature. @@ -5059,7 +5080,7 @@ A function member ([§12.6](expressions.md#126-function-members)) implemented us An iterator block may be used as the body of a function member as long as the return type of the corresponding function member is one of the enumerator interfaces ([§15.14.2](classes.md#15142-enumerator-interfaces)) or one of the enumerable interfaces ([§15.14.3](classes.md#15143-enumerable-interfaces)). It may occur as a *method_body*, *operator_body* or *accessor_body*, whereas events, instance constructors, static constructors and finalizers may not be implemented as iterators. -When a function member is implemented using an iterator block, it is a compile-time error for the formal parameter list of the function member to specify any `ref` or `out` parameters. +When a function member is implemented using an iterator block, it is a compile-time error for the formal parameter list of the function member to specify any `in`, `out`, or `ref` parameters. ### 15.14.2 Enumerator interfaces @@ -5175,7 +5196,7 @@ An enumerable object provides an implementation of the `GetEnumerator` methods o A method ([§15.6](classes.md#156-methods)) or anonymous function ([§12.19](expressions.md#1219-anonymous-function-expressions)) with the `async` modifier is called an ***async function***. In general, the term ***async*** is used to describe any kind of function that has the `async` modifier. -It is a compile-time error for the formal parameter list of an async function to specify any `ref` or `out` parameters. +It is a compile-time error for the formal parameter list of an async function to specify any `in`, `out`, or `ref` parameters. The *return_type* of an async method shall be either `void` or a ***task type***. For an async method that returns a value, a task type shall be generic. For an async method that does not return a value, a task type shall not be generic. Such types are referred to in this specification as `«TaskType»` and `«TaskType»`, respectively. (The Standard library types `System.Threading.Tasks.Task` and types constructed from `System.Threading.Tasks.Task` are task types.) A task type shall be a class or struct type that is associated with a ***task builder type*** via the attribute `System.Runtime.CompilerServices.AsyncMethodBuilder`. Such types are referred to in this specification as `«TaskBuilderType»` and `«TaskBuilderType»`. diff --git a/standard/conversions.md b/standard/conversions.md index 15db2859e..04c55f398 100644 --- a/standard/conversions.md +++ b/standard/conversions.md @@ -919,9 +919,9 @@ An implicit conversion exists from a method group ([§12.2](expressions.md#122-e The compile-time application of the conversion from a method group `E` to a delegate type `D` is described in the following. - A single method `M` is selected corresponding to a method invocation ([§12.8.9.2](expressions.md#12892-method-invocations)) of the form `E(A)`, with the following modifications: - - The argument list `A` is a list of expressions, each classified as a variable and with the type and modifier (`ref` or `out`) of the corresponding parameter in the *formal_parameter_list* of `D` — excepting parameters of type `dynamic`, where the corresponding expression has the type `object` instead of `dynamic`. + - The argument list `A` is a list of expressions, each classified as a variable and with the type and modifier (`in`, `out`, or `ref`) of the corresponding parameter in the *formal_parameter_list* of `D` — excepting parameters of type `dynamic`, where the corresponding expression has the type `object` instead of `dynamic`. - The candidate methods considered are only those methods that are applicable in their normal form and do not omit any optional parameters ([§12.6.4.2](expressions.md#12642-applicable-function-member)). Thus, candidate methods are ignored if they are applicable only in their expanded form, or if one or more of their optional parameters do not have a corresponding parameter in `D`. -- A conversion is considered to exist if the algorithm of [§12.8.9.2](expressions.md#12892-method-invocations) produces a single best method `M` which is compatible ([§20.4](delegates.md#204-delegate-compatibility)) with `D`. +- A conversion is considered to exist if the algorithm of [§12.8.9.2](expressions.md#12892-method-invocations) produces a single best method `M` having the same number of parameters as `D`. - If the selected method `M` is an instance method, the instance expression associated with `E` determines the target object of the delegate. - If the selected method `M` is an extension method which is denoted by means of a member access on an instance expression, that instance expression determines the target object of the delegate. - The result of the conversion is a value of type `D`, namely a delegate that refers to the selected method and target object. diff --git a/standard/delegates.md b/standard/delegates.md index 68fa803bd..b39e760be 100644 --- a/standard/delegates.md +++ b/standard/delegates.md @@ -86,9 +86,9 @@ Except for instantiation, any operation that can be applied to a class or class A method or delegate type `M` is ***compatible*** with a delegate type `D` if all of the following are true: -- `D` and `M` have the same number of parameters, and each parameter in `D` has the same `ref` or `out` modifiers as the corresponding parameter in `M`. -- For each value parameter (a parameter with no `ref` or `out` modifier), an identity conversion ([§10.2.2](conversions.md#1022-identity-conversion)) or implicit reference conversion ([§10.2.8](conversions.md#1028-implicit-reference-conversions)) exists from the parameter type in `D` to the corresponding parameter type in `M`. -- For each `ref` or `out` parameter, the parameter type in `D` is the same as the parameter type in `M`. +- `D` and `M` have the same number of parameters, and each parameter in `D` has the same `in`, `out`, or `ref` modifiers as the corresponding parameter in `M`. +- For each value parameter, an identity conversion ([§10.2.2](conversions.md#1022-identity-conversion)) or implicit reference conversion ([§10.2.8](conversions.md#1028-implicit-reference-conversions)) exists from the parameter type in `D` to the corresponding parameter type in `M`. +- For each `in`, `out` or `ref` parameter, the parameter type in `D` is the same as the parameter type in `M`. - If `D` and `M` are returns-by-value ([§15.6.1](classes.md#1561-general), [§20.2](delegates.md#202-delegate-declarations)), an identity or implicit reference conversion exists from the return type of `M` to the return type of `D`. - Otherwise, if `D` and `M` are both returns-by-ref, an identity conversion exists between the return type of `M` and the return type of `D`, and both have a *return_type* preceded by `ref readonly`, or both have a *return_type* preceded by `ref` only. diff --git a/standard/documentation-comments.md b/standard/documentation-comments.md index 80c29b478..0ecc5a82d 100644 --- a/standard/documentation-comments.md +++ b/standard/documentation-comments.md @@ -695,7 +695,7 @@ The documentation generator observes the following rules when it generates the I - For methods and properties with arguments, the argument list follows, enclosed in parentheses. For those without arguments, the parentheses are omitted. The arguments are separated by commas. The encoding of each argument is the same as a CLI signature, as follows: - Arguments are represented by their documentation name, which is based on their fully qualified name, modified as follows: - Arguments that represent generic types have an appended “`'`” character followed by the number of type parameters - - Arguments having the `out` or `ref` modifier have an `@` following their type name. Arguments passed by value or via `params` have no special notation. + - Arguments having the `in`, `out` or `ref` modifier have an `@` following their type name. Arguments passed by value or via `params` have no special notation. - Arguments that are arrays are represented as `[` *lowerbound* `:` *size* `,` … `,` *lowerbound* `:` *size* `]` where the number of commas is the rank less one, and the lower bounds and size of each dimension, if known, are represented in decimal. If a lower bound or size is not specified, it is omitted. If the lower bound and size for a particular dimension are omitted, the “`:`” is omitted as well. Jagged arrays are represented by one “`[]`” per level. - Arguments that have pointer types other than `void` are represented using a `*` following the type name. A `void` pointer is represented using a type name of `System.Void`. - Arguments that refer to generic type parameters defined on types are encoded using the “`` ` ``” character followed by the zero-based index of the type parameter. @@ -854,7 +854,7 @@ namespace Acme } public static void M0() { ... } - public void M1(char c, out float f, ref ValueType v) { ... } + public void M1(char c, out float f, ref ValueType v, in int i) { ... } public void M2(short[] x1, int[,] x2, long[][] x3) { ... } public void M3(long[][] x3, Widget[][,,] x4) { ... } public unsafe void M4(char *pc, Color **pf) { ... } @@ -881,7 +881,7 @@ IDs: "M:Acme.ValueType.M(System.Int32)" "M:Acme.Widget.NestedClass.M(System.Int32)" "M:Acme.Widget.M0" -"M:Acme.Widget.M1(System.Char,System.Single@,Acme.ValueType@)" +"M:Acme.Widget.M1(System.Char,System.Single@,Acme.ValueType@,System.Int32@)" "M:Acme.Widget.M2(System.Int16[],System.Int32[0:,0:],System.Int64[][])" "M:Acme.Widget.M3(System.Int64[][],Acme.Widget[0:,0:,0:][])" "M:Acme.Widget.M4(System.Char*,Color**)" diff --git a/standard/expressions.md b/standard/expressions.md index 9bfd291c0..2a75bd446 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -66,6 +66,8 @@ The following operations in C# are subject to binding: When no dynamic expressions are involved, C# defaults to static binding, which means that the compile-time types of subexpressions are used in the selection process. However, when one of the subexpressions in the operations listed above is a dynamic expression, the operation is instead dynamically bound. +It is a compile time error if a method invocation is dynamically bound and any of the parameters, including the receiver, has the `in` modifier. + ### 12.3.2 Binding-time Static binding takes place at compile-time, whereas dynamic binding takes place at run-time. In the following subclauses, the term ***binding-time*** refers to either compile-time or run-time, depending on when the binding takes place. @@ -529,7 +531,7 @@ Every function member and delegate invocation includes an argument list, which p - For events, the argument list consists of the expression specified as the right operand of the `+=` or `-=` operator. - For user-defined operators, the argument list consists of the single operand of the unary operator or the two operands of the binary operator. -The arguments of properties ([§15.7](classes.md#157-properties)), events ([§15.8](classes.md#158-events)), and user-defined operators ([§15.10](classes.md#1510-operators)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)). The arguments of indexers ([§15.9](classes.md#159-indexers)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)) or parameter arrays ([§15.6.2.5](classes.md#15625-parameter-arrays)). Reference and output parameters are not supported for these categories of function members. +The arguments of properties ([§15.7](classes.md#157-properties)), events ([§15.8](classes.md#158-events)), and user-defined operators ([§15.10](classes.md#1510-operators)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)). The arguments of indexers ([§15.9](classes.md#159-indexers)) are always passed as value parameters ([§15.6.2.2](classes.md#15622-value-parameters)) or parameter arrays ([§15.6.2.5](classes.md#15625-parameter-arrays)). Input, output, and reference parameters are not supported for these categories of function members. The arguments of an instance constructor, method, indexer, or delegate invocation are specified as an *argument_list*: @@ -548,6 +550,7 @@ argument_name argument_value : expression + | 'in' variable_reference | 'ref' variable_reference | 'out' variable_reference ; @@ -557,13 +560,14 @@ An *argument_list* consists of one or more *argument*s, separated by commas. Eac The *argument_value* can take one of the following forms: -- An *expression*, indicating that the argument is passed as a value parameter ([§15.6.2.2](classes.md#15622-value-parameters)). +- An *expression*, indicating that the argument is passed as a value parameter or is transformed into an input parameter and then passed as that, as determined by ([§12.6.4.2](expressions.md#12642-applicable-function-member) and described in [§12.6.2.3](expressions.md#12623-run-time-evaluation-of-argument-lists). +- The keyword `in` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as an input parameter (§method-input-parameters-new-clause). A variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) before it can be passed as an input parameter. - The keyword `ref` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as a reference parameter ([§15.6.2.3](classes.md#15623-reference-parameters)). A variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) before it can be passed as a reference parameter. - The keyword `out` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as an output parameter ([§15.6.2.4](classes.md#15624-output-parameters)). A variable is considered definitely assigned ([§9.4](variables.md#94-definite-assignment)) following a function member invocation in which the variable is passed as an output parameter. -The form determines the ***parameter-passing mode*** of the argument: *value*, *reference*, or *output*, respectively. +The form determines the ***parameter-passing mode*** of the argument: *value*, *input*, *reference*, or *output*, respectively. However, as mentioned above, an argument with value passing mode, might be transformed into one with input passing mode. -Passing a volatile field ([§15.5.4](classes.md#1554-volatile-fields)) as a reference parameter or output parameter causes a warning, since the field may not be treated as volatile by the invoked method. +Passing a volatile field ([§15.5.4](classes.md#1554-volatile-fields)) as an input, output, or reference parameter causes a warning, since the field may not be treated as volatile by the invoked method. #### 12.6.2.2 Corresponding parameters @@ -594,8 +598,24 @@ The corresponding parameters for function member arguments are established as fo During the run-time processing of a function member invocation ([§12.6.6](expressions.md#1266-function-member-invocation)), the expressions or variable references of an argument list are evaluated in order, from left to right, as follows: -- For a value parameter, the argument expression is evaluated and an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) to the corresponding parameter type is performed. The resulting value becomes the initial value of the value parameter in the function member invocation. -- For a reference or output parameter, the variable reference is evaluated and the resulting storage location becomes the storage location represented by the parameter in the function member invocation. If the variable reference given as a reference or output parameter is an array element of a *reference_type*, a run-time check is performed to ensure that the element type of the array is identical to the type of the parameter. If this check fails, a `System.ArrayTypeMismatchException` is thrown. +- For a value parameter, if the parameter’s passing mode is value + - the argument expression is evaluated and an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) to the corresponding parameter type is performed. The resulting value becomes the initial value of the value parameter in the function member invocation. + - otherwise, the parameter’s passing mode is input, in which case, a storage location is created with the same type as that of the corresponding parameter. The argument expression is evaluated and an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) to the corresponding parameter type is performed. The resulting value is stored within that storage location. That storage location is represented by the input parameter in the function member invocation. + + > *Example*: Given the following declarations and method calls: + > + > ```csharp + > public static void M1(in int p1) { … } + > int i = 10; + > M1(i); // transformed to a temporary input argument + > M1(i + 5); // transformed to a temporary input argument + > ``` + > + > In each method call, an unnamed `int` variable is created, initialized with the argument’s value, and then passed as an input argument. See [§12.6.4.2](expressions.md#12642-applicable-function-member) and §better-argument-passing-mode-new-clause. + > + > *end example* + +- For an input, output, or reference parameter, the variable reference is evaluated and the resulting storage location becomes the storage location represented by the parameter in the function member invocation. If the variable reference given as an output, or reference is an array element of a *reference_type*, a run-time check is performed to ensure that the element type of the array is identical to the type of the parameter. If this check fails, a `System.ArrayTypeMismatchException` is thrown. Methods, indexers, and instance constructors may declare their right-most parameter to be a parameter array ([§15.6.2.5](classes.md#15625-parameter-arrays)). Such function members are invoked either in their normal form or in their expanded form depending on which is applicable ([§12.6.4.2](expressions.md#12642-applicable-function-member)): @@ -631,7 +651,7 @@ The expressions of an argument list are always evaluated in textual order. > > *end example* -The array co-variance rules ([§17.6](arrays.md#176-array-covariance)) permit a value of an array type `A[]` to be a reference to an instance of an array type `B[]`, provided an implicit reference conversion exists from `B` to `A`. Because of these rules, when an array element of a *reference_type* is passed as a reference or output parameter, a run-time check is required to ensure that the actual element type of the array is *identical* to that of the parameter. +The array co-variance rules ([§17.6](arrays.md#176-array-covariance)) permit a value of an array type `A[]` to be a reference to an instance of an array type `B[]`, provided an implicit reference conversion exists from `B` to `A`. Because of these rules, when an array element of a *reference_type* is passed as an input, output, or reference parameter, a run-time check is required to ensure that the actual element type of the array is *identical* to that of the parameter. > *Example*: In the following code > @@ -679,7 +699,7 @@ When a function member with a parameter array is invoked in its expanded form wi > > *end example* -When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. +When arguments are omitted from a function member with corresponding optional parameters, the default arguments of the function member declaration are implicitly passed. (This can involve the creation of a storage location, as described above.) > *Note*: Because these are always constant, their evaluation will not impact the evaluation of the remaining arguments. *end note* @@ -737,7 +757,8 @@ For each of the method arguments `Eᵢ`: - If `Eᵢ` is an anonymous function, an *explicit parameter type inference* ([§12.6.3.8](expressions.md#12638-explicit-parameter-type-inferences)) is made *from* `Eᵢ` *to* `Tᵢ` - Otherwise, if `Eᵢ` has a type `U` and `xᵢ` is a value parameter ([§15.6.2.2](classes.md#15622-value-parameters)) then a *lower-bound inference* ([§12.6.3.10](expressions.md#126310-lower-bound-inferences)) is made *from* `U` *to* `Tᵢ`. -- Otherwise, if `Eᵢ` has a type `U` and `xᵢ` is a reference ([§15.6.2.3](classes.md#15623-reference-parameters)) or output ([§15.6.2.4](classes.md#15624-output-parameters)) parameter then an *exact inference* ([§12.6.3.9](expressions.md#12639-exact-inferences)) is made *from* `U` *to* `Tᵢ`. +- Otherwise, if `Eᵢ` has a type `U` and `xᵢ` is a reference parameter ([§15.6.2.3](classes.md#15623-reference-parameters)), or output parameter ([§15.6.2.4](classes.md#15624-output-parameters)) then an *exact inference* ([§12.6.3.9](expressions.md#12639-exact-inferences)) is made *from* `U` *to* `Tᵢ`. +- Otherwise, if `Eᵢ` has a type `U` and `xᵢ` is an input parameter (§method-input-parameters-new-clause) then a *lower bound inference* ([§12.6.3.10](expressions.md#126310-lower-bound-inferences)) is made *from* `U` *to* `Tᵢ`. A new storage location is created following the rules of §12.6.2.2 on corresponding parameters. - Otherwise, no inference is made for this argument. #### 12.6.3.3 The second phase @@ -980,16 +1001,40 @@ A function member is said to be an ***applicable function member*** with respect - For each argument in `A`, the parameter-passing mode of the argument is identical to the parameter-passing mode of the corresponding parameter, and - for a value parameter or a parameter array, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from the argument expression to the type of the corresponding parameter, or - for a `ref` or `out` parameter, there is an identity conversion between the type of the argument expression (if any) and the type of the corresponding parameter + - for an `in` parameter when the corresponding argument has the `in` modifier, there is an identity conversion between the type of the argument expression (if any) and the type of the corresponding parameter + - for an `in` parameter when the corresponding argument omits the `in` modifier, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)), excluding dynamic implicit conversions (§10.2.10) exists from the argument expressions to the type of the corresponding parameter. For a function member that includes a parameter array, if the function member is applicable by the above rules, it is said to be applicable in its ***normal form***. If a function member that includes a parameter array is not applicable in its normal form, the function member might instead be applicable in its ***expanded form***: - The expanded form is constructed by replacing the parameter array in the function member declaration with zero or more value parameters of the element type of the parameter array such that the number of arguments in the argument list `A` matches the total number of parameters. If `A` has fewer arguments than the number of fixed parameters in the function member declaration, the expanded form of the function member cannot be constructed and is thus not applicable. -- Otherwise, the expanded form is applicable if for each argument in `A` the parameter-passing mode of the argument is identical to the parameter-passing mode of the corresponding parameter, and - - for a fixed value parameter or a value parameter created by the expansion, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from the argument expression to the type of the corresponding parameter, or - - for a `ref` or `out` parameter, there is an identity conversion between the type of the argument expression (if any) and the type of the corresponding parameter. - -Additional rules determine whether a method is applicable or not based on the context of the expression: +- Otherwise, the expanded form is applicable if for each argument in `A`, one of the following is true: + - the parameter-passing mode of the argument is identical to the parameter-passing mode of the corresponding parameter, and + - for a fixed value parameter or a value parameter created by the expansion, an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) exists from the argument expression to the type of the corresponding parameter, or + - for `in`, `out`, or `ref` parameter, the type of the argument expression is identical to the type of the corresponding parameter. + - the parameter-passing mode of the argument is value, and the parameter-passing mode of the corresponding parameter is input, and an implicit conversion ([§10.2](conversions.md#102-implicit-conversions)) excluding dynamic implicit conversions (§10.2.10) exists from the argument expression to the type of the corresponding parameter +> *Example*: Given the following declarations and method calls: +> +> ```csharp +> public static void M1(int p1) { … } +> public static void M1(in int p1) { … } +> int i = 10; uint ui = 34U; +> +> M1(in i); // M1(in int) is applicable +> M1(in ui); // no exact type match, so M1(in int) is not applicable +> M1(i); // M1(int) and M1(in int) are applicable +> M1(i + 5); // M1(int) and M1(in int) are applicable +> M1(100u); // no implicit conversion exists, so M1(int) is not applicable +> +> public static void M2(in int p1) { … } +> +> M2(in i); // M2(in int) is applicable +> M2(i); // M2(in int) is applicable +> M2(i + 5); // M2(in int) is applicable +> ``` +> +> *end example* + - A static method is only applicable if the method group results from a *simple_name* or a *member_access* through a type. - An instance method is only applicable if the method group results from a *simple_name*, a *member_access* through a variable or value, or a *base_access*. - If the method group results from a *simple_name*, an instance method is only applicable if `this` access is permitted [§12.8.13](expressions.md#12813-this-access). @@ -1025,6 +1070,19 @@ In case the parameter type sequences `{P₁, P₂, ..., Pᵥ}` and `{Q₁, Q₂ - Otherwise if one member is a non-lifted operator and the other is a lifted operator, the non-lifted one is better. - If neither function member was found to be better, and all parameters of `Mᵥ` have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in `Mₓ`, then `Mᵥ` is better than `Mₓ`. Otherwise, no function member is better. +#### §better-argument-passing-mode-new-clause Better argument-passing mode + +It is permitted to have corresponding parameters in two overloaded methods differ only by parameter-passing mode provided one of the two parameters has value-passing mode, as follows: + +```csharp +public static void M1(int p1) { … } +public static void M1(in int p1) { … } +``` + +Given `int i = 10;`, according to [§12.6.4.2](expressions.md#12642-applicable-function-member), the calls `M1(i)` and `M1(i + 5)` result in both overloads being applicable. In such cases, the method with the parameter-passing mode of value is the ***better parameter-passing mode choice***. + +> *Note*: No such choice need exist for arguments of input, output, or reference passing modes, as those arguments only match the exact same parameter passing modes. *end note* + #### 12.6.4.4 Better conversion from expression Given an implicit conversion `C₁` that converts from an expression `E` to a type `T₁`, and an implicit conversion `C₂` that converts from an expression `E` to a type `T₂`, `C₁` is a ***better conversion*** than `C₂` if one of the following holds: @@ -1969,7 +2027,7 @@ element_access ; ``` -The *argument_list* of an *element_access* is not allowed to contain `ref` or `out` arguments. +The *argument_list* of an *element_access* is not allowed to contain `in`, `out`, or `ref` arguments. An *element_access* is dynamically bound ([§12.3.3](expressions.md#1233-dynamic-binding)) if at least one of the following holds: @@ -2068,9 +2126,11 @@ A *this_access* is permitted only in the *block* of an instance constructor, an - When `this` is used in a *primary_expression* within an instance method or instance accessor of a class, it is classified as a value. The type of the value is the instance type ([§15.3.2](classes.md#1532-the-instance-type)) of the class within which the usage occurs, and the value is a reference to the object for which the method or accessor was invoked. - When `this` is used in a *primary_expression* within an instance constructor of a struct, it is classified as a variable. The type of the variable is the instance type ([§15.3.2](classes.md#1532-the-instance-type)) of the struct within which the usage occurs, and the variable represents the struct being constructed. - If the constructor declaration has no constructor initializer, the `this` variable behaves exactly the same as an `out` parameter of the struct type. In particular, this means that the variable shall be definitely assigned in every execution path of the instance constructor. - - Otherwise, the `this` variable behaves exactly the same as a `ref` parameter of the struct type. In particular, this means that the variable is considered initially assigned. + - Otherwise, the `this` variable behaves exactly the same as a `ref` parameter of the struct type. In particular, this means that the variable is considered initially assigned, and can't be reassigned. - When `this` is used in a *primary_expression* within an instance method or instance accessor of a struct, it is classified as a variable. The type of the variable is the instance type ([§15.3.2](classes.md#1532-the-instance-type)) of the struct within which the usage occurs. - - If the method or accessor is not an iterator ([§15.14](classes.md#1514-iterators)) or async function ([§15.15](classes.md#1515-async-functions)), the `this` variable represents the struct for which the method or accessor was invoked, and behaves exactly the same as a `ref` parameter of the struct type. + - If the method or accessor is not an iterator ([§15.14](classes.md#1514-iterators)) or async function ([§15.15](classes.md#1515-async-functions)), the `this` variable represents the struct for which the method or accessor was invoked. + - If the struct is a `readonly struct`, the `this` variable behaves exactly the same as an `in` parameter of the struct type + - Otherwise the `this` variable behaves exactly the same as a `ref` parameter of the struct type - If the method or accessor is an iterator or async function, the `this` variable represents a *copy* of the struct for which the method or accessor was invoked, and behaves exactly the same as a *value* parameter of the struct type. Use of `this` in a *primary_expression* in a context other than the ones listed above is a compile-time error. In particular, it is not possible to refer to `this` in a static method, a static property accessor, or in a *variable_initializer* of a field declaration. @@ -4644,6 +4704,7 @@ explicit_anonymous_function_parameter anonymous_function_parameter_modifier : 'ref' | 'out' + | 'in' ; implicit_anonymous_function_signature @@ -4731,7 +4792,7 @@ Note also that conversion to an expression tree type, even if compatible, may st The body (*expression* or *block*) of an anonymous function is subject to the following rules: - If the anonymous function includes a signature, the parameters specified in the signature are available in the body. If the anonymous function has no signature it can be converted to a delegate type or expression type having parameters ([§10.7](conversions.md#107-anonymous-function-conversions)), but the parameters cannot be accessed in the body. -- Except for `ref` or `out` parameters specified in the signature (if any) of the nearest enclosing anonymous function, it is a compile-time error for the body to access a `ref` or `out` parameter. +- Except for `in`, `out` or `ref` parameters specified in the signature (if any) of the nearest enclosing anonymous function, it is a compile-time error for the body to access an `in`, `out`, or `ref` parameter. - When the type of `this` is a struct type, it is a compile-time error for the body to access `this`. This is true whether the access is explicit (as in `this.x`) or implicit (as in `x` where `x` is an instance member of the struct). This rule simply prohibits such access and does not affect whether member lookup results in a member of the struct. - The body has access to the outer variables ([§12.19.6](expressions.md#12196-outer-variables)) of the anonymous function. Access of an outer variable will reference the instance of the variable that is active at the time the *lambda_expression* or *anonymous_method_expression* is evaluated ([§12.19.7](expressions.md#12197-evaluation-of-anonymous-function-expressions)). - It is a compile-time error for the body to contain a `goto` statement, a `break` statement, or a `continue` statement whose target is outside the body or within the body of a contained anonymous function. diff --git a/standard/interfaces.md b/standard/interfaces.md index 4411a8f25..c797dcab0 100644 --- a/standard/interfaces.md +++ b/standard/interfaces.md @@ -236,7 +236,7 @@ All interface members implicitly have public access. It is a compile-time error An *interface_declaration* creates a new declaration space ([§7.3](basic-concepts.md#73-declarations)), and the type parameters and *interface_member_declaration*s immediately contained by the *interface_declaration* introduce new members into this declaration space. The following rules apply to *interface_member_declaration*s: - The name of a type parameter in the *type_parameter_list* of an interface declaration shall differ from the names of all other type parameters in the same *type_parameter_list* and shall differ from the names of all members of the interface. -- The name of a method shall differ from the names of all properties and events declared in the same interface. In addition, the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of a method shall differ from the signatures of all other methods declared in the same interface, and two methods declared in the same interface may not have signatures that differ solely by `ref` and `out`. +- The name of a method shall differ from the names of all properties and events declared in the same interface. In addition, the signature ([§7.6](basic-concepts.md#76-signatures-and-overloading)) of a method shall differ from the signatures of all other methods declared in the same interface, and two methods declared in the same interface may not have signatures that differ solely by `in`, `out`, and `ref`. - The name of a property or event shall differ from the names of all other members declared in the same interface. - The signature of an indexer shall differ from the signatures of all other indexers declared in the same interface. diff --git a/standard/structs.md b/standard/structs.md index a3ad2ff5f..303277931 100644 --- a/standard/structs.md +++ b/standard/structs.md @@ -185,7 +185,7 @@ A variable of a struct type directly contains the data of the struct, whereas a > > *end example* -With classes, it is possible for two variables to reference the same object, and thus possible for operations on one variable to affect the object referenced by the other variable. With structs, the variables each have their own copy of the data (except in the case of `ref` and `out` parameter variables), and it is not possible for operations on one to affect the other. Furthermore, except when explicitly nullable ([§8.3.12](types.md#8312-nullable-value-types)), it is not possible for values of a struct type to be `null`. +With classes, it is possible for two variables to reference the same object, and thus possible for operations on one variable to affect the object referenced by the other variable. With structs, the variables each have their own copy of the data (except in the case of `in`, `out` and `ref` parameter variables), and it is not possible for operations on one to affect the other. Furthermore, except when explicitly nullable ([§8.3.12](types.md#8312-nullable-value-types)), it is not possible for values of a struct type to be `null`. > *Note*: If a struct contains a field of reference type then the contents of the object referenced can be altered by other operations. However the value of the field itself, i.e., which object it references, cannot be changed through a mutation of a different struct value. *end note* @@ -236,7 +236,7 @@ Function members in a struct cannot be abstract or virtual, and the `override` m Assignment to a variable of a struct type creates a *copy* of the value being assigned. This differs from assignment to a variable of a class type, which copies the reference but not the object identified by the reference. -Similar to an assignment, when a struct is passed as a value parameter or returned as the result of a function member, a copy of the struct is created. A struct may be passed by reference to a function member using a `ref` or `out` parameter. +Similar to an assignment, when a struct is passed as a value parameter or returned as the result of a function member, a copy of the struct is created. A struct may be passed by reference to a function member using an `in`, `out`, or `ref` parameter. When a property or indexer of a struct is the target of an assignment, the instance expression associated with the property or indexer access shall be classified as a variable. If the `instance` expression is classified as a value, a compile-time error occurs. This is described in further detail in [§12.21.2](expressions.md#12212-simple-assignment). diff --git a/standard/unsafe-code.md b/standard/unsafe-code.md index 94ba08f93..0a28a70f5 100644 --- a/standard/unsafe-code.md +++ b/standard/unsafe-code.md @@ -267,7 +267,7 @@ In precise terms, a fixed variable is one of the following: All other variables are classified as moveable variables. -A static field is classified as a moveable variable. Also, a `ref` or `out` parameter is classified as a moveable variable, even if the argument given for the parameter is a fixed variable. Finally, a variable produced by dereferencing a pointer is always classified as a fixed variable. +A static field is classified as a moveable variable. Also, an `in`, `out`, or `ref` parameter is classified as a moveable variable, even if the argument given for the parameter is a fixed variable. Finally, a variable produced by dereferencing a pointer is always classified as a fixed variable. ## 23.5 Pointer conversions diff --git a/standard/variables.md b/standard/variables.md index 8e7305b61..8e1098b19 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -12,7 +12,7 @@ As described in the following subclauses, variables are either ***initially assi ### 9.2.1 General -C# defines seven categories of variables: static variables, instance variables, array elements, value parameters, reference parameters, output parameters, and local variables. The subclauses that follow describe each of these categories. +C# defines eight categories of variables: static variables, instance variables, array elements, value parameters, input parameters, reference parameters, output parameters, and local variables. The subclauses that follow describe each of these categories. > *Example*: In the following code > @@ -23,17 +23,15 @@ C# defines seven categories of variables: static variables, instance variables, > public static int x; > int y; > -> void F(int[] v, int a, ref int b, out int c) +> void F(int[] v, int a, ref int b, out int c, in int d) > { > int i = 1; -> c = a + b++; +> c = a + b++ + d; > } > } > ``` > -> `x` is a static variable, `y` is an instance variable, `v[0]` is an array element, `a` is a value parameter, `b` is a reference parameter, `c` is an output parameter, and `i` is a local variable. -> -> *end example* +> `x` is a static variable, `y` is an instance variable, `v[0]` is an array element, `a` is a value parameter, `b` is a reference parameter, `c` is an output parameter, `d` is an input parameter, and `i` is a local variable. *end example* ### 9.2.2 Static variables @@ -73,7 +71,7 @@ For the purpose of definite-assignment checking, an array element is considered ### 9.2.5 Value parameters -A parameter declared without a `ref` or `out` modifier is a ***value parameter***. +A parameter declared without an `in`, `out`, or `ref` modifier is a ***value parameter***. A value parameter comes into existence upon invocation of the function member (method, instance constructor, accessor, or operator) or anonymous function to which the parameter belongs, and is initialized with the value of the argument given in the invocation. A value parameter normally ceases to exist when execution of the function body completes. However, if the value parameter is captured by an anonymous function ([§12.19.6.2](expressions.md#121962-captured-outer-variables)), its lifetime extends at least until the delegate or expression tree created from that anonymous function is eligible for garbage collection. @@ -83,7 +81,7 @@ For the purpose of definite-assignment checking, a value parameter is considered A parameter declared with a `ref` modifier is a ***reference parameter***. -A reference parameter does not create a new storage location. Instead, a reference parameter represents the same storage location as the variable given as the argument in the function member, anonymous function, or local function invocation. Thus, the value of a reference parameter is always the same as the underlying variable. +A reference parameter refers to the variable given as the argument in the function member, anonymous function, or local function invocation. The variable given as the argument is the ***referent*** of the reference parameter. Thus, the value of a reference parameter is always the same as the underlying variable. The following definite-assignment rules apply to reference parameters. @@ -98,7 +96,7 @@ For a `struct` type, within an instance method or instance accessor ([§12.2.1]( A parameter declared with an `out` modifier is an ***output parameter***. -An output parameter does not create a new storage location. Instead, an output parameter represents the same storage location as the variable given as the argument in the function member or delegate invocation. Thus, the value of an output parameter is always the same as the underlying variable. +An output parameter refers to the variable given as the argument in the function member or delegate invocation. The variable given as the argument is the ***referent*** of the output parameter. Thus, the value of an output parameter is always the same as the underlying variable. The following definite-assignment rules apply to output parameters. @@ -109,7 +107,16 @@ The following definite-assignment rules apply to output parameters. - Within a function member or anonymous function, an output parameter is considered initially unassigned. - Every output parameter of a function member, anonymous function, or local function shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) before the function member, anonymous function, or local function returns normally. -Within an instance constructor of a struct type, the `this` keyword behaves exactly as an output or reference parameter of the struct type, depending on whether the constructor declaration includes a constructor initializer ([§12.8.13](expressions.md#12813-this-access)). +### §input-parameters-new-clause Input parameters + +A parameter declared with an `in` modifier is an ***input parameter***. + +An input parameter refers to the variable given as the argument in the function member or delegate invocation. The variable given as the argument is the ***referent*** of the input parameter. Thus, the value of an input parameter is always the same as the underlying variable. + +The following definite assignment rules apply to input parameters. + +- A variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) before it can be passed as an input parameter in a function member or delegate invocation. +- Within a function member, anonymous function, or local function an input parameter is considered initially assigned. ### 9.2.8 Local variables @@ -226,6 +233,8 @@ Definite assignment is a requirement in the following contexts: - the variable is a *struct_type* variable and occurs as the left operand of a member access. - A variable shall be definitely assigned at each location where it is passed as a reference parameter. > *Note*: This ensures that the function member being invoked can consider the reference parameter initially assigned. *end note* +- A variable shall be definitely assigned at each location where it is passed as an input parameter. + > *Note*: This ensures that the function member being invoked can consider the input parameter initially assigned. *end note* - All output parameters of a function member shall be definitely assigned at each location where the function member returns (through a return statement or through execution reaching the end of the function member body). > *Note*: This ensures that function members do not return undefined values in output parameters, thus enabling the compiler to consider a function member invocation that takes a variable as an output parameter equivalent to an assignment to the variable. *end note* - The `this` variable of a *struct_type* instance constructor shall be definitely assigned at each location where that instance constructor returns. @@ -240,6 +249,7 @@ The following categories of variables are classified as initially assigned: - Array elements. - Value parameters. - Reference parameters. +- Input parameters. - Variables declared in a `catch` clause or a `foreach` statement. ### 9.4.3 Initially unassigned variables @@ -666,11 +676,11 @@ or an object-creation expression *expr* of the form: new «type» ( «arg₁», «arg₂», … , «argₓ» ) ``` -- For an invocation expression, the definite-assignment state of *v* before *primary_expression* is the same as the state of *v* before *expr*. -- For an invocation expression, the definite-assignment state of *v* before *arg₁* is the same as the state of *v* after *primary_expression*. -- For an object-creation expression, the definite-assignment state of *v* before *arg₁* is the same as the state of *v* before *expr*. -- For each argument *argᵢ*, the definite-assignment state of *v* after *argᵢ* is determined by the normal expression rules, ignoring any `ref` or `out` modifiers. -- For each argument *argᵢ* for any *i* greater than one, the definite-assignment state of *v* before *argᵢ* is the same as the state of *v* after *argᵢ₋₁*. +- For an invocation expression, the definite assignment state of *v* before *primary_expression* is the same as the state of *v* before *expr*. +- For an invocation expression, the definite assignment state of *v* before *arg₁* is the same as the state of *v* after *primary_expression*. +- For an object creation expression, the definite assignment state of *v* before *arg₁* is the same as the state of *v* before *expr*. +- For each argument *argᵢ*, the definite assignment state of *v* after *argᵢ* is determined by the normal expression rules, ignoring any `in`, `out`, or `ref` modifiers. +- For each argument *argᵢ* for any *i* greater than one, the definite assignment state of *v* before *argᵢ* is the same as the state of *v* after *argᵢ₋₁*. - If the variable *v* is passed as an `out` argument (i.e., an argument of the form “out *v*”) in any of the arguments, then the state of *v* after *expr* is definitely assigned. Otherwise, the state of *v* after *expr* is the same as the state of *v* after *argₓ*. - For array initializers ([§12.8.16.5](expressions.md#128165-array-creation-expressions)), object initializers ([§12.8.16.3](expressions.md#128163-object-initializers)), collection initializers ([§12.8.16.4](expressions.md#128164-collection-initializers)) and anonymous object initializers ([§12.8.16.7](expressions.md#128167-anonymous-object-creation-expressions)), the definite-assignment state is determined by the expansion that these constructs are defined in terms of. @@ -845,9 +855,9 @@ For an expression *expr* of the form: For a *lambda_expression* or *anonymous_method_expression* *expr* with a body (either *block* or *expression*) *body*: -- The definite-assignment state of a parameter is the same as for a parameter of a named method ([§9.2.6](variables.md#926-reference-parameters), [§9.2.7](variables.md#927-output-parameters)). -- The definite-assignment state of an outer variable *v* before *body* is the same as the state of *v* before *expr*. That is, definite-assignment state of outer variables is inherited from the context of the anonymous function. -- The definite-assignment state of an outer variable *v* after *expr* is the same as the state of *v* before *expr*. +- The definite assignment state of a parameter is the same as for a parameter of a named method ([§9.2.6](variables.md#926-reference-parameters), [§9.2.7](variables.md#927-output-parameters), §input-parameters-new-clause). +- The definite assignment state of an outer variable *v* before *body* is the same as the state of *v* before *expr*. That is, definite assignment state of outer variables is inherited from the context of the anonymous function. +- The definite assignment state of an outer variable *v* after *expr* is the same as the state of *v* before *expr*. > *Example*: The example >