diff --git a/.markdownlint.json b/.markdownlint.json index 9c380c21c..e395bac86 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -12,9 +12,6 @@ ] }, - "MD009" : false, - "MD010" : false, - "MD012" : false, "MD022" : false, "MD027" : false, "MD028" : false, diff --git a/README.md b/README.md index 238737372..c0bafb4d3 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ This folder contains an ANTLR grammar-extraction tool and support files. - GetGrammar.bat - the Windows batch file that invokes ExtractGrammar on each md file of the C# specification that contains ANTLR grammar blocks, in clause order, inserting some md headers and such along the way. The result is a file called grammar.md, **which is a direct replacement for that file in the specification repo**. -> A minor wart: There is an extraneous blank line at the beginning of each of the lexical, syntactic, and unsafe grammars. At a glance, the amount of programming effort probably needed to stop this from happening seems to be *huge* compared with simply deleting those three lines manually. +> A minor wart: There is an extraneous blank line at the beginning of each of the lexical, syntactic, and unsafe grammars. At a glance, the amount of programming effort probably needed to stop this from happening seems to be *huge* compared with simply deleting those three lines manually. ### MarkdownConverter diff --git a/admin/guidelines-for-spec-writing-and-formatting.md b/admin/guidelines-for-spec-writing-and-formatting.md index 663ffc4be..f04d1933b 100644 --- a/admin/guidelines-for-spec-writing-and-formatting.md +++ b/admin/guidelines-for-spec-writing-and-formatting.md @@ -1,10 +1,10 @@ # Guidelines to Spec Writing and Formatting -1. Put meta-information about the standard (e.g., what "implementation" means) in the Terms-and-definitions clause. C#-specific terms should be italicized on their first use only in the narrative. -1. Don't say the same thing normatively in more than one place; say it once and point to that place, as needed. -1. For requirements, use *shall* and *shall not*. Inside informative (that is, non-normative) text, **never** use *shall*, use *must* instead. -1. Examples and Notes marked as such are informative, and requirements *must* be clear *without* them. Ask yourself, "Does the normative text standalone if all the examples and notes are removed?" -1. While examples are good, keep them small, simple, and narrowly focused without using unnecessary features. A spec is *not* a tutorial! -1. Avoid using quoted text, as in "natural type." If that is a term, except for its first use it should be in regular font without the quotes. In general, such quote marks dilute the contents, especially if their use suggests, "sort of like this thingie." Rather than use an approximate description in quotes, choose the right term or other English text. -1. Use singular instead of plural: For example, don't say, "Tuple types are declared using the following syntax:"; instead, say, "A tuple type is declared using the following syntax:". For the most part, the plural form is quite clear, but there can be cases where it isn't, so it's best to use the singular form. -1. A section should contain either subsections or text, but never both. Consider the case in which we have a section with *no* subsections: ## Section S; some text. Later one or more subsections are added, resulting in ## Section S; some text; ### Subsection S.1; some text; ### Subsection S.2; some text. This is *bad*, as a subsequent reference to S is ambiguous; is it to that whole section or is it to the preamble text at the start of that section? As such, you need to put the preamble text in a new subsection (which we've called "General") at the start of that section. +1. Put meta-information about the standard (e.g., what "implementation" means) in the Terms-and-definitions clause. C#-specific terms should be italicized on their first use only in the narrative. +1. Don't say the same thing normatively in more than one place; say it once and point to that place, as needed. +1. For requirements, use *shall* and *shall not*. Inside informative (that is, non-normative) text, **never** use *shall*, use *must* instead. +1. Examples and Notes marked as such are informative, and requirements *must* be clear *without* them. Ask yourself, "Does the normative text standalone if all the examples and notes are removed?" +1. While examples are good, keep them small, simple, and narrowly focused without using unnecessary features. A spec is *not* a tutorial! +1. Avoid using quoted text, as in "natural type." If that is a term, except for its first use it should be in regular font without the quotes. In general, such quote marks dilute the contents, especially if their use suggests, "sort of like this thingie." Rather than use an approximate description in quotes, choose the right term or other English text. +1. Use singular instead of plural: For example, don't say, "Tuple types are declared using the following syntax:"; instead, say, "A tuple type is declared using the following syntax:". For the most part, the plural form is quite clear, but there can be cases where it isn't, so it's best to use the singular form. +1. A section should contain either subsections or text, but never both. Consider the case in which we have a section with *no* subsections: ## Section S; some text. Later one or more subsections are added, resulting in ## Section S; some text; ### Subsection S.1; some text; ### Subsection S.2; some text. This is *bad*, as a subsequent reference to S is ambiguous; is it to that whole section or is it to the preamble text at the start of that section? As such, you need to put the preamble text in a new subsection (which we've called "General") at the start of that section. diff --git a/standard/arrays.md b/standard/arrays.md index 9dded84f0..fc57f0f1c 100644 --- a/standard/arrays.md +++ b/standard/arrays.md @@ -43,7 +43,7 @@ In effect, the *rank_specifier*s are read from left to right *before* the final > *Example*: The type in `T[][,,][,]` is a single-dimensional array of three-dimensional arrays of two-dimensional arrays of `int`. *end example* -At run-time, a value of an array type can be `null` or a reference to an instance of that array type. +At run-time, a value of an array type can be `null` or a reference to an instance of that array type. > *Note*: Following the rules of [§16.6](arrays.md#166-array-covariance), the value may also be a reference to a covariant array type. *end note* diff --git a/standard/attributes.md b/standard/attributes.md index 2587c33a8..908116463 100644 --- a/standard/attributes.md +++ b/standard/attributes.md @@ -4,7 +4,7 @@ Much of the C# language enables the programmer to specify declarative information about the entities defined in the program. For example, the accessibility of a method in a class is specified by decorating it with the *method_modifier*s `public`, `protected`, `internal`, and `private`. -C# enables programmers to invent new kinds of declarative information, called ***attributes***. Programmers can then attach attributes to various program entities, and retrieve attribute information in a run-time environment. +C# enables programmers to invent new kinds of declarative information, called ***attributes***. Programmers can then attach attributes to various program entities, and retrieve attribute information in a run-time environment. > *Note*: For instance, a framework might define a `HelpAttribute` attribute that can be placed on certain program elements (such as classes and methods) to provide a mapping from those program elements to their documentation. *end note* @@ -75,7 +75,7 @@ The attribute `AttributeUsage` ([§21.5.2](attributes.md#2152-the-attributeusage > } > ``` > defines a multi-use attribute class named `AuthorAttribute`. The example -> +> > ```csharp > [Author("Brian Kernighan"), Author("Dennis Ritchie")] > class Class1 @@ -108,7 +108,7 @@ class X : Attribute { ... } ### 21.2.3 Positional and named parameters -Attribute classes can have ***positional parameters*** and ***named parameters***. Each public instance constructor for an attribute class defines a valid sequence of positional parameters for that attribute class. Each non-static public read-write field and property for an attribute class defines a named parameter for the attribute class. For a property to define a named parameter, that property shall have both a public get accessor and a public set accessor. +Attribute classes can have ***positional parameters*** and ***named parameters***. Each public instance constructor for an attribute class defines a valid sequence of positional parameters for that attribute class. Each non-static public read-write field and property for an attribute class defines a named parameter for the attribute class. For a property to define a named parameter, that property shall have both a public get accessor and a public set accessor. > *Example*: The example > ```csharp @@ -132,7 +132,7 @@ Attribute classes can have ***positional parameters*** and ***named parameters** > } > ``` > defines an attribute class named `HelpAttribute` that has one positional parameter, `url`, and one named parameter, `Topic`. Although it is non-static and public, the property `Url` does not define a named parameter, since it is not read-write. -> +> > This attribute class might be used as follows: > ```csharp > [Help("http://www.mycompany.com/.../Class1.htm")] @@ -309,7 +309,8 @@ By convention, attribute classes are named with a suffix of `Attribute`. An *att - If the right-most identifier of the *attribute_name* is a verbatim identifier ([§6.4.3](lexical-structure.md#643-identifiers)), then the *attribute_name* is resolved as a *type_name* ([§7.8](basic-concepts.md#78-namespace-and-type-names)). If the result is not a type derived from `System.Attribute`, a compile-time error occurs. - Otherwise, - The *attribute_name* is resolved as a *type_name* ([§7.8](basic-concepts.md#78-namespace-and-type-names)) except any errors are suppressed. If this resolution is successful and results in a type derived from `System.Attribute` then the type is the result of this step. - - The characters `Attribute` are appended to the right-most identifier in the *attribute_name* and the resulting string of tokens is resolved as a *type_name* ([§7.8](basic-concepts.md#78-namespace-and-type-names)) except any errors are suppressed. If this resolution is successful and results in a type derived from `System.Attribute` then the type is the result of this step. + - The characters `Attribute` are appended to the right-most identifier in the *attribute_name* and the resulting string of tokens is resolved as a *type_name* ([§7.8](basic-concepts.md#78-namespace-and-type-names)) except any errors are suppressed. If this resolution is successful and results in a type derived from `System.Attribute` then the type is the result of this step. + If exactly one of the two steps above results in a type derived from `System.Attribute`, then that type is the result of the *attribute_name*. Otherwise a compile-time error occurs. *Example*: If an attribute class is found both with and without this suffix, an ambiguity is present, and a compile-time error results. If the *attribute_name* is spelled such that its right-most *identifier* is a verbatim identifier ([§6.4.3](lexical-structure.md#643-identifiers)), then only an attribute without a suffix is matched, thus enabling such an ambiguity to be resolved. The example @@ -452,7 +453,7 @@ The compilation of an *attribute* with attribute class `T`, *positional_argumen - For each *named_argument* `Arg` in `N`: - Let `Name` be the *identifier* of the *named_argument* `Arg`. - `Name` shall identify a non-static read-write public field or property on `T`. If `T` has no such field or property, then a compile-time error occurs. -- If any of the values within *positional_argument_list* `P` or one of the values within *named_argument_list* `N` is of type `System.String` and the value is not well-formed as defined by the Unicode Standard, it is implementation-defined whether the value compiled is equal to the run-time value retrieved ([§21.4.3](attributes.md#2143-run-time-retrieval-of-an-attribute-instance)). +- If any of the values within *positional_argument_list* `P` or one of the values within *named_argument_list* `N` is of type `System.String` and the value is not well-formed as defined by the Unicode Standard, it is implementation-defined whether the value compiled is equal to the run-time value retrieved ([§21.4.3](attributes.md#2143-run-time-retrieval-of-an-attribute-instance)). > *Note*: As an example, a string which contains a high surrogate UTF-16 code unit which isn’t immediately followed by a low surrogate code unit is not well-formed. *end note* - Store the following information (for run-time instantiation of the attribute) in the assembly output by the compiler as a result of compiling the program containing the attribute: the attribute class `T`, the instance constructor `C` on `T`, the *positional_argument_list * `P`, the *named_argument_list* `N`, and the associated program entity `E`, with the values resolved completely at compile-time. @@ -505,9 +506,7 @@ A small number of attributes affect the language in some way. These attributes i - `System.AttributeUsageAttribute` ([§21.5.2](attributes.md#2152-the-attributeusage-attribute)), which is used to describe the ways in which an attribute class can be used. - `System.Diagnostics.ConditionalAttribute` ([§21.5.3](attributes.md#2153-the-conditional-attribute)), is a multi-use attribute class which is used to define conditional methods and conditional attribute classes. This attribute indicates a condition by testing a conditional compilation symbol. - `System.ObsoleteAttribute` ([§21.5.4](attributes.md#2154-the-obsolete-attribute)), which is used to mark a member as obsolete. -- `System.Runtime.CompilerServices.CallerLineNumberAttribute` ([§21.5.5.2](attributes.md#21552-the-callerlinenumber-attribute)), - `System.Runtime.CompilerServices.CallerFilePathAttribute` ([§21.5.5.3](attributes.md#21553-the-callerfilepath-attribute)), and - `System.Runtime.CompilerServices.CallerMemberNameAttribute` ([§21.5.5.4](attributes.md#21554-the-callermembername-attribute)), which are used to supply information about the calling context to optional parameters. +- `System.Runtime.CompilerServices.CallerLineNumberAttribute` ([§21.5.5.2](attributes.md#21552-the-callerlinenumber-attribute)), `System.Runtime.CompilerServices.CallerFilePathAttribute` ([§21.5.5.3](attributes.md#21553-the-callerfilepath-attribute)), and `System.Runtime.CompilerServices.CallerMemberNameAttribute` ([§21.5.5.4](attributes.md#21554-the-callermembername-attribute)), which are used to supply information about the calling context to optional parameters. An execution environment may provide additional implementation-specific attributes that affect the execution of a C# program. @@ -810,7 +809,7 @@ For invocations that occur within declarations of instance constructors, static ## 21.6 Attributes for interoperation For interoperation with other languages, an indexer may be implemented using indexed properties. If no `IndexerName` attribute is present for an indexer, then the name `Item` is used by default. The `IndexerName` attribute enables a developer to override this default and specify a different name. - + > *Example*: By default, an indexer’s name is `Item`. This can be overridden, as follows: > ```csharp > [System.Runtime.CompilerServices.IndexerName("TheItem")] diff --git a/standard/basic-concepts.md b/standard/basic-concepts.md index 02d11a89f..1e04a4eee 100644 --- a/standard/basic-concepts.md +++ b/standard/basic-concepts.md @@ -294,7 +294,7 @@ The accessibility domain of a nested member `M` declared in a type `T` within > } > ``` > the classes and members have the following accessibility domains: -> +> > - The accessibility domain of `A` and `A.X` is unlimited. > - The accessibility domain of `A.Y`, `B`, `B.X`, `B.Y`, `B.C`, `B.C.X`, and `B.C.Y` is the program text of the containing program. > - The accessibility domain of `A.Z` is the program text of `A`. @@ -569,7 +569,7 @@ Within the scope of a local variable, it is a compile-time error to refer to the > In the `F` method above, the first assignment to `i` specifically does not refer to the field declared in the outer scope. Rather, it refers to the local variable and it results in a compile-time error because it textually precedes the declaration of the variable. In the `G` method, the use of `j` in the initializer for the declaration of `j` is valid because the use does not precede the *local_variable_declarator*. In the `H` method, a subsequent *local_variable_declarator* correctly refers to a local variable declared in an earlier *local_variable_declarator* within the same *local_variable_declaration*. *end example* > *Note*: The scoping rules for local variables and local constants are designed to guarantee that the meaning of a name used in an expression context is always the same within a block. If the scope of a local variable were to extend only from its declaration to the end of the block, then in the example above, the first assignment would assign to the instance variable and the second assignment would assign to the local variable, possibly leading to compile-time errors if the statements of the block were later to be rearranged.) -> +> > The meaning of a name within a block may differ based on the context in which the name is used. In the example > ```csharp > using System; @@ -768,7 +768,7 @@ The meaning of a *namespace_or_type_name* is determined as follows: - Otherwise, the *namespace_or_type_name* is of the form `N.I` or of the form `N.I`. `N` is first resolved as a *namespace_or_type_name*. If the resolution of `N` is not successful, a compile-time error occurs. Otherwise, `N.I` or `N.I` is resolved as follows: - If `x` is zero and `N` refers to a namespace and `N` contains a nested namespace with name `I`, then the *namespace_or_type_name* refers to that nested namespace. - Otherwise, if `N` refers to a namespace and `N` contains an accessible type having name `I` and `x` type parameters, then the *namespace_or_type_name* refers to that type constructed with the given type arguments. - - Otherwise, if `N` refers to a (possibly constructed) class or struct type and `N` or any of its base classes contain a nested accessible type having name `I` and `x` type parameters, then the *namespace_or_type_name* refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected. + - Otherwise, if `N` refers to a (possibly constructed) class or struct type and `N` or any of its base classes contain a nested accessible type having name `I` and `x` type parameters, then the *namespace_or_type_name* refers to that type constructed with the given type arguments. If there is more than one such type, the type declared within the more derived type is selected. > *Note*: If the meaning of `N.I` is being determined as part of resolving the base class specification of `N` then the direct base class of `N` is considered to be `object` ([§14.2.4.2](classes.md#14242-base-classes)). *end note* - Otherwise, `N.I` is an invalid *namespace_or_type_name*, and a compile-time error occurs. @@ -836,7 +836,7 @@ C# employs automatic memory management, which frees developers from manually all > *Note*: The C# compiler and the garbage collector might choose to analyze code to determine which references to an object might be used in the future. For instance, if a local variable that is in scope is the only existing reference to an object, but that local variable is never referred to in any possible continuation of execution from the current execution point in the procedure, the garbage collector might (but is not required to) treat the object as no longer in use. *end note* 1. Once the object is eligible for finalization, at some unspecified later time the finalizer ([§14.13](classes.md#1413-finalizers)) (if any) for the object is run. Under normal circumstances the finalizer for the object is run once only, though implementation-specific APIs may allow this behavior to be overridden. 1. Once the finalizer for an object is run, if neither the object nor any of its instance fields can be accessed by any possible continuation of execution, including the running of finalizers, the object is considered inaccessible and the object becomes eligible for collection. - > *Note*: An object which could previously not be accessed may become accessible again due to its finalizer. An example of this is provided below. *end note* + > *Note*: An object which could previously not be accessed may become accessible again due to its finalizer. An example of this is provided below. *end note* 1. Finally, at some time after the object becomes eligible for collection, the garbage collector frees the memory associated with that object. The garbage collector maintains information about object usage, and uses this information to make memory management decisions, such as where in memory to locate a newly created object, when to relocate an object, and when an object is no longer in use or inaccessible. diff --git a/standard/classes.md b/standard/classes.md index 250a19371..fe9d9c025 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -186,7 +186,7 @@ When a *class_type* is included in the *class_base*, it specifies the direct bas > ``` > Class `A` is said to be the direct base class of `B`, and `B` is said to be derived from `A`. Since `A` does not explicitly specify a direct base class, its direct base class is implicitly `object`. *end example* -For a constructed class type, including a nested type declared within a generic type declaration ([§14.3.9.7](classes.md#14397-nested-types-in-generic-classes)), if a base class is specified in the generic class declaration, the base class of the constructed type is obtained by substituting, for each *type_parameter* in the base class declaration, the corresponding *type_argument* of the constructed type. +For a constructed class type, including a nested type declared within a generic type declaration ([§14.3.9.7](classes.md#14397-nested-types-in-generic-classes)), if a base class is specified in the generic class declaration, the base class of the constructed type is obtained by substituting, for each *type_parameter* in the base class declaration, the corresponding *type_argument* of the constructed type. > *Example*: Given the generic class declarations > ```csharp @@ -370,7 +370,7 @@ A primary constraint can be a class type or the ***reference type constraint*** The reference type constraint specifies that a type argument used for the type parameter shall be a reference type. All class types, interface types, delegate types, array types, and type parameters known to be a reference type (as defined below) satisfy this constraint. -The value type constraint specifies that a type argument used for the type parameter shall be a non-nullable value type. All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. Note that although classified as a value type, a nullable value type ([§8.3.11](types.md#8311-nullable-value-types)) does not satisfy the value type constraint. A type parameter having the value type constraint shall not also have the *constructor_constraint*, although it may be used as a type argument for another type parameter with a *constructor_constraint*. +The value type constraint specifies that a type argument used for the type parameter shall be a non-nullable value type. All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. Note that although classified as a value type, a nullable value type ([§8.3.11](types.md#8311-nullable-value-types)) does not satisfy the value type constraint. A type parameter having the value type constraint shall not also have the *constructor_constraint*, although it may be used as a type argument for another type parameter with a *constructor_constraint*. > *Note*: The `System.Nullable` type specifies the non-nullable value type constraint for `T`. Thus, recursively constructed types of the forms `T??` and `Nullable>` are prohibited. *end note* @@ -485,7 +485,7 @@ It is a compile-time error for *type_parameter_constraints* having a *primary_co > ``` > *end example* -The ***dynamic erasure*** of a type `C` is type `Cₓ` constructed as follows: +The ***dynamic erasure*** of a type `C` is type `Cₓ` constructed as follows: - If `C` is a nested type `Outer.Inner` then `Cₓ` is a nested type `Outerₓ.Innerₓ`. - If `C` `Cₓ`is a constructed type `G` with type arguments `A¹, ..., Aⁿ` then `Cₓ` is the constructed type `G`. @@ -672,7 +672,7 @@ A *class_declaration* creates a new declaration space ([§7.3](basic-concepts.md - The name of a type parameter in the *type_parameter_list* of a class declaration shall differ from the names of all other type parameters in the same *type_parameter_list* and shall differ from the name of the class and the names of all members of the class. -- The name of a type shall differ from the names of all non-type members declared in the same class. If two or more type declarations share the same fully qualified name, the declarations shall have the `partial` modifier ([§14.2.7](classes.md#1427-partial-declarations)) and these declarations combine to define a single type. +- The name of a type shall differ from the names of all non-type members declared in the same class. If two or more type declarations share the same fully qualified name, the declarations shall have the `partial` modifier ([§14.2.7](classes.md#1427-partial-declarations)) and these declarations combine to define a single type. > *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. @@ -685,7 +685,7 @@ A *class_declaration* creates a new declaration space ([§7.3](basic-concepts.md - The signature of an operator shall differ from the signatures of all other operators declared in the same class. -The inherited members of a class ([§14.3.4](classes.md#1434-inheritance)) are not part of the declaration space of a class. +The inherited members of a class ([§14.3.4](classes.md#1434-inheritance)) are not part of the declaration space of a class. > *Note*: Thus, a derived class is allowed to declare a member with the same name or signature as an inherited member (which in effect hides the inherited member). *end note* @@ -837,7 +837,7 @@ Types that are used in the declaration of a member are called the ***constituent ### 14.3.8 Static and instance members -Members of a class are either ***static members*** or ***instance members***. +Members of a class are either ***static members*** or ***instance members***. > *Note*: Generally speaking, it is useful to think of static members as belonging to classes and instance members as belonging to objects (instances of classes). *end note* @@ -1250,13 +1250,13 @@ The *type* of a constant shall be at least as accessible as the constant itself The value of a constant is obtained in an expression using a *simple_name* ([§11.7.4](expressions.md#1174-simple-names)) or a *member_access* ([§11.7.6](expressions.md#1176-member-access)). -A constant can itself participate in a *constant_expression*. Thus, a constant may be used in any construct that requires a *constant_expression*. +A constant can itself participate in a *constant_expression*. Thus, a constant may be used in any construct that requires a *constant_expression*. > *Note*: Examples of such constructs include `case` labels, `goto case` statements, `enum` member declarations, attributes, and other constant declarations. *end note* > *Note*: As described in [§11.20](expressions.md#1120-constant-expressions), a *constant_expression* is an expression that can be fully evaluated at compile-time. Since the only way to create a non-null value of a *reference_type* other than `string` is to apply the `new` operator, and since the `new` operator is not permitted in a *constant_expression*, the only possible value for constants of *reference_type*s other than `string` is `null`. *end note* -When a symbolic name for a constant value is desired, but when the type of that value is not permitted in a constant declaration, or when the value cannot be computed at compile-time by a *constant_expression*, a readonly field ([§14.5.3](classes.md#1453-readonly-fields)) may be used instead. +When a symbolic name for a constant value is desired, but when the type of that value is not permitted in a constant declaration, or when the value cannot be computed at compile-time by a *constant_expression*, a readonly field ([§14.5.3](classes.md#1453-readonly-fields)) may be used instead. > *Note*: The versioning semantics of `const` and `readonly` differ ([§14.5.3.3](classes.md#14533-versioning-of-constants-and-static-readonly-fields)). *end note* @@ -1295,7 +1295,7 @@ Constants are permitted to depend on other constants within the same program as > public const int Z = A.Y + 1; > } > ``` -> the compiler first evaluates `A.Y`, then evaluates `B.Z`, and finally evaluates `A.X`, producing the values `10`, `11`, and `12`. *end example* +> the compiler first evaluates `A.Y`, then evaluates `B.Z`, and finally evaluates `A.X`, producing the values `10`, `11`, and `12`. *end example* Constant declarations may depend on constants from other programs, but such dependencies are only possible in one direction. @@ -1727,7 +1727,6 @@ Grammar notes: > *Note*: The overlapping of, and priority between, alternatives here is solely for descriptive convenience; the grammar rules could be elaborated to remove the overlap. ANTLR, and other grammar systems, adopt the same convenience and so *method_body* has the specified semantics automatically. - A *method_declaration* may include a set of *attributes* ([§21](attributes.md#21-attributes)) and a valid combination of the four access modifiers ([§14.3.6](classes.md#1436-access-modifiers)), the `new` ([§14.3.5](classes.md#1435-the-new-modifier)), `static` ([§14.6.3](classes.md#1463-static-and-instance-methods)), `virtual` ([§14.6.4](classes.md#1464-virtual-methods)), `override` ([§14.6.5](classes.md#1465-override-methods)), `sealed` ([§14.6.6](classes.md#1466-sealed-methods)), `abstract` ([§14.6.7](classes.md#1467-abstract-methods)), `extern` ([§14.6.8](classes.md#1468-external-methods)) and `async` ([§14.15](classes.md#1415-async-functions)) modifiers. A declaration has a valid combination of modifiers if all of the following are true: @@ -1847,7 +1846,7 @@ There are four kinds of formal parameters: - Output parameters, which are declared with the `out` 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 `ref` and `out` modifiers are part of a method’s signature, but the `params` modifier is not. #### 14.6.2.2 Value parameters @@ -2051,7 +2050,7 @@ When performing overload resolution, a method with a parameter array might be ap > In the example, two of the possible expanded forms of the method with a parameter array are already included in the class as regular methods. These expanded forms are therefore not considered when performing overload resolution, and the first and third method invocations thus select the regular methods. When a class declares a method with a parameter array, it is not uncommon to also include some of the expanded forms as regular methods. By doing so, it is possible to avoid the allocation of an array instance that occurs when an expanded form of a method with a parameter array is invoked. *end example* > An array is a reference type, so the value passed for a parameter array can be `null`. -> +> > *Example*: The example: > ```csharp > using System; @@ -2806,7 +2805,7 @@ Based on the presence or absence of the get and set accessors, a property is cla - A property that includes both a get accessor and a set accessor is said to be a ***read-write property***. - A property that has only a get accessor is said to be a ***read-only property***. It is a compile-time error for a read-only property to be the target of an assignment. -- A property that has only a set accessor is said to be a ***write-only property***. Except as the target of an assignment, it is a compile-time error to reference a write-only property in an expression. +- A property that has only a set accessor is said to be a ***write-only property***. Except as the target of an assignment, it is a compile-time error to reference a write-only property in an expression. > *Note*: The pre- and postfix `++` and `--` operators and compound assignment operators cannot be applied to write-only properties, since these operators read the old value of their operand before they write the new one. *end note* @@ -2950,7 +2949,7 @@ Unlike public fields, properties provide a separation between an object’s inte > } > ``` > the value of the `Next` property depends on the number of times the property has previously been accessed. Thus, accessing the property produces an observable side effect, and the property should be implemented as a method instead. -> +> > The “no side-effects” convention for get accessors doesn’t mean that get accessors should always be written simply to return values stored in fields. Indeed, get accessors often compute the value of a property by accessing multiple fields or invoking methods. However, a properly designed get accessor performs no actions that cause observable changes in the state of the object. *end example* Properties can be used to delay initialization of a resource until the moment it is first referenced. @@ -3538,7 +3537,7 @@ Indexer declarations are subject to the same rules as method declarations ([§14 The modifiers `virtual`, `override`, and `abstract` are mutually exclusive except in one case. The `abstract` and `override` modifiers may be used together so that an abstract indexer can override a virtual one. -The *type* of an indexer declaration specifies the element type of the indexer introduced by the declaration. +The *type* of an indexer declaration specifies the element type of the indexer introduced by the declaration. > *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* @@ -3554,7 +3553,7 @@ Based on the presence or absence of get and set accessors, an indexer is classif - An indexer that includes both a get accessor and a set accessor is said to be a ***read-write indexer***. - An indexer that has only a get accessor is said to be a ***read-only indexer***. It is a compile-time error for a read-only indexer to be the target of an assignment. -- An indexer that has only a set accessor is said to be a ***write-only indexer***. Except as the target of an assignment, it is a compile-time error to reference a write-only indexer in an expression. +- An indexer that has only a set accessor is said to be a ***write-only indexer***. Except as the target of an assignment, it is a compile-time error to reference a write-only indexer in an expression. 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. @@ -3628,7 +3627,7 @@ When an indexer declaration includes an `extern` modifier, the indexer is said t > } > ``` > An instance of the `BitArray` class consumes substantially less memory than a corresponding `bool[]` (since each value of the former occupies only one bit instead of the latter’s one `byte`), but it permits the same operations as a `bool[]`. -> +> > The following `CountPrimes` class uses a `BitArray` and the classical “sieve” algorithm to compute the number of primes between 2 and a given maximum: > ```csharp > class CountPrimes @@ -4009,7 +4008,7 @@ All instance constructors (except those for class` object`) implicitly include a - An instance constructor initializer of the form `base(`*argument_list*`)` (where *argument_list* is optional) causes an instance constructor from the direct base class to be invoked. That constructor is selected using *argument_list* and the overload resolution rules of [§11.6.4](expressions.md#1164-overload-resolution). The set of candidate instance constructors consists of all the accessible instance constructors of the direct base class. If this set is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs. - An instance constructor initializer of the form `this(`*argument_list*`)` (where *argument_list* is optional) invokes another instance constructor from the same class. The constructor is selected using *argument_list* and the overload resolution rules of [§11.6.4](expressions.md#1164-overload-resolution). The set of candidate instance constructors consists of all instance constructors declared in the class itself. If the resulting set of applicable instance constructors is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs. If an instance constructor declaration invokes itself through a chain of one or more constructor initializers, a compile-time error occurs. -If an instance constructor has no constructor initializer, a constructor initializer of the form `base()` is implicitly provided. +If an instance constructor has no constructor initializer, a constructor initializer of the form `base()` is implicitly provided. > *Note*: Thus, an instance constructor declaration of the form > ```csharp @@ -4162,7 +4161,7 @@ Variable initializers are transformed into assignment statements, and these assi ### 14.11.5 Default constructors -If a class contains no instance constructor declarations, a default instance constructor is automatically provided. That default constructor simply invokes a constructor of the direct base class, as if it had a constructor initializer of the form `base()`. If the class is abstract then the declared accessibility for the default constructor is protected. Otherwise, the declared accessibility for the default constructor is public. +If a class contains no instance constructor declarations, a default instance constructor is automatically provided. That default constructor simply invokes a constructor of the direct base class, as if it had a constructor initializer of the form `base()`. If the class is abstract then the declared accessibility for the default constructor is protected. Otherwise, the declared accessibility for the default constructor is public. > *Note*: Thus, the default constructor is always of the form > ```csharp @@ -4172,7 +4171,7 @@ If a class contains no instance constructor declarations, a default instance con > ```csharp > public C(): base() {} > ``` -> where `C` is the name of the class. *end note* +> where `C` is the name of the class. *end note* If overload resolution is unable to determine a unique best candidate for the base-class constructor initializer then a compile-time error occurs. @@ -4316,7 +4315,7 @@ It is possible to construct circular dependencies that allow static fields with > } > ``` > produces the output -> +> > ```console > X = 1, Y = 2 > ``` @@ -4547,7 +4546,7 @@ When a function member returning an enumerable interface type is implemented usi An enumerable object is typically an instance of a compiler-generated enumerable class that encapsulates the code in the iterator block and implements the enumerable interfaces, but other methods of implementation are possible. If an enumerable class is generated by the compiler, that class will be nested, directly or indirectly, in the class containing the function member, it will have private accessibility, and it will have a name reserved for compiler use ([§6.4.3](lexical-structure.md#643-identifiers)). -An enumerable object may implement more interfaces than those specified above. +An enumerable object may implement more interfaces than those specified above. > *Note*: For example, an enumerable object may also implement `IEnumerator` and `IEnumerator`, enabling it to serve as both an enumerable and an enumerator. Typically, such an implementation would return its own instance (to save allocations) from the first call to `GetEnumerator`. Subsequent invocations of `GetEnumerator`, if any, would return a new class instance, typically of the same class, so that calls to different enumerator instances will not affect each other. It cannot return the same instance even if the previous enumerator has already enumerated past the end of the sequence, since all future calls to an exhausted enumerator must throw exceptions. *end note* diff --git a/standard/conversions.md b/standard/conversions.md index 05e16e20b..7105913eb 100644 --- a/standard/conversions.md +++ b/standard/conversions.md @@ -212,7 +212,7 @@ Boxing a value of a *nullable_value_type* produces a null reference if it is the > Console.Write(((Point)box).x); > ``` > will output the value 10 on the console because the implicit boxing operation that occurs in the assignment of `p` to `box` causes the value of `p` to be copied. Had `Point` been declared a `class` instead, the value 20 would be output because `p` and `box` would reference the same instance. -> +> > The analogy of a boxing class should not be used as more than a helpful tool for picturing how boxing works conceptually. There are numerous subtle differences between the behavior described by this specification and the behavior that would result from boxing being implemented in precisely this manner. *end note* ### 10.2.10 Implicit dynamic conversions @@ -459,7 +459,7 @@ For a *type_parameter* `T` that is known to be a reference type ([§14.2.5](clas - From the effective base class `C` of `T` to `T` and from any base class of `C` to `T`. - From any *interface_type* to `T`. - From `T` to any *interface_type* `I` provided there isn’t already an implicit reference conversion from `T` to `I`. -- From a *type_parameter* `U` to `T` provided that `T` depends on `U` ([§14.2.5](classes.md#1425-type-parameter-constraints)). +- From a *type_parameter* `U` to `T` provided that `T` depends on `U` ([§14.2.5](classes.md#1425-type-parameter-constraints)). > *Note*: Since `T` is known to be a reference type, within the scope of `T`, the run-time type of U will always be a reference type, even if `U` is not known to be a reference type at compile-time. *end note* For a *type_parameter* `T` that is *not* known to be a reference type ([§14.2.5](classes.md#1425-type-parameter-constraints)), the following conversions involving `T` are considered to be unboxing conversions ([§10.3.6](conversions.md#1036-unboxing-conversions)) at compile-time. At run-time, if `T` is a value type, the conversion is executed as an unboxing conversion. At run-time, if `T` is a reference type, the conversion is executed as an explicit reference conversion or identity conversion. @@ -727,13 +727,13 @@ Specifically, an anonymous function `F` is compatible with a delegate type `D` > Func> f4 = async x => x + 1; // Ok > ``` > the parameter and return types of each anonymous function are determined from the type of the variable to which the anonymous function is assigned. -> +> > The first assignment successfully converts the anonymous function to the delegate type `Func` because, when `x` is given type `int`, `x + 1` is a valid expression that is implicitly convertible to type `int`. -> +> > Likewise, the second assignment successfully converts the anonymous function to the delegate type Func because the result of `x + 1` (of type `int`) is implicitly convertible to type `double`. -> +> > However, the third assignment is a compile-time error because, when `x` is given type `double`, the result of `x + 1` (of type `double`) is not implicitly convertible to type `int`. -> +> > The fourth assignment successfully converts the anonymous async function to the delegate type `Func>` because the result of `x + 1` (of type `int`) is implicitly convertible to the effective return type `int` of the async lambda, which has a return type `Task`. *end example* A lambda expression `F` is compatible with an expression tree type `Expression` if `F` is compatible with the delegate type `D`. This does not apply to anonymous methods, only lambda expressions. @@ -825,13 +825,13 @@ The compile-time application of the conversion from a method group `E` to a del > } > ``` > The assignment to `d1` implicitly converts the method group `F` to a value of type `D1`. -> +> > The assignment to `d2` shows how it is possible to create a delegate to a method that has less derived (contravariant) parameter types and a more derived (covariant) return type. -> +> > The assignment to `d3` shows how no conversion exists if the method is not applicable. -> +> > The assignment to `d4` shows how the method must be applicable in its normal form. -> +> > The assignment to `d5` shows how parameter and return types of the delegate and method are allowed to differ only for reference types. > *end example* @@ -874,7 +874,7 @@ Method groups may influence overload resolution, and participate in type inferen The run-time evaluation of a method group conversion proceeds as follows: -- If the method selected at compile-time is an instance method, or it is an extension method which is accessed as an instance method, +- If the method selected at compile-time is an instance method, or it is an extension method which is accessed as an instance method, the target object of the delegate is determined from the instance expression associated with `E`: - The instance expression is evaluated. If this evaluation causes an exception, no further steps are executed. - If the instance expression is of a *reference_type*, the value computed by the instance expression becomes the target object. If the selected method is an instance method and the target object is `null`, a `System.NullReferenceException` is thrown and no further steps are executed. diff --git a/standard/delegates.md b/standard/delegates.md index a6759ad99..f2cb3dd74 100644 --- a/standard/delegates.md +++ b/standard/delegates.md @@ -86,7 +86,7 @@ A method or delegate type `M` is ***compatible*** with a delegate type `D` if al This definition of consistency allows covariance in return type and contravariance in parameter types. -> *Example*: +> *Example*: > ```csharp > delegate int D1(int i, double d); > delegate int D2(int c, double d); @@ -109,7 +109,7 @@ This definition of consistency allows covariance in return type and contravarian > ``` > The methods `A.M1` and `B.M1` are compatible with both the delegate types `D1` and `D2`, since they have the same return type and parameter list. The methods `B.M2`, `B.M3`, and `B.M4` are incompatible with the delegate types `D1` and `D2`, since they have different return types or parameter lists. The methods `B.M5` and `B.M6` are both compatible with delegate type `D3`. *end example* -> *Example*: +> *Example*: > ```csharp > delegate bool Predicate(T value); > @@ -137,7 +137,7 @@ This definition of consistency allows covariance in return type and contravarian > } > ``` > The `Print` method is compatible with the `Action` delegate type because any invocation of an `Action` delegate would also be a valid invocation of the `Print` method. -> +> > If the signature of the `Print` method above were changed to `Print(object value, bool prependTimestamp = false)` for example, the `Print` method would no longer be compatible with `Action` by the rules of this clause. *end note* ## 19.5 Delegate instantiation @@ -148,7 +148,7 @@ An instance of a delegate is created by a *delegate_creation_expression* ([§11. - The target object (which cannot be `null`) and instance method referenced in the *delegate_creation_expression*, or - Another delegate ([§11.7.15.6](expressions.md#117156-delegate-creation-expressions)). -> *Example*: +> *Example*: > ```csharp > delegate void D(int x); > @@ -169,7 +169,7 @@ An instance of a delegate is created by a *delegate_creation_expression* ([§11. > } > } > ``` -> *end example* +> *end example* The set of methods encapsulated by a delegate instance is called an *invocation list*. When a delegate instance is created from a single method, it encapsulates that method, and its invocation list contains only one entry. However, when two non-`null` delegate instances are combined, their invocation lists are concatenated—in the order left operand then right operand—to form a new invocation list, which contains two or more entries. @@ -206,15 +206,15 @@ Delegates are combined using the binary `+` ([§11.9.5](expressions.md#1195-add > } > ``` > When `cd1` and `cd2` are instantiated, they each encapsulate one method. When `cd3` is instantiated, it has an invocation list of two methods, `M1` and `M2`, in that order. `cd4`’s invocation list contains `M1`, `M2`, and `M1`, in that order. For `cd5`, the invocation list contains `M1`, `M2`, `M1`, `M1`, and `M2`, in that order. -> +> > When `cd1` and `cd2` are instantiated, they each encapsulate one method. When `cd3` is instantiated, it has an invocation list of two methods, `M1` and `M2`, in that order. `cd4`s invocation list contains `M1`, `M2`, and `M1`, in that order. For `cd5` the invocation list contains `M1`, `M2`, `M1`, `M1`, and `M2`, in that order. -> +> > When creating a delegate from another delegate with a *delegate_creation_expression* the result has an invocation list with a different structure from the original, but which results in the same methods being invoked in the same order. When `td3` is created from `cd3` its invocation list has just one member, but that member is a list of the methods `M1` and `M2` and those methods are invoked by `td3` in the same order as they are invoked by `cd3`. Similarly when `td4` is instantiated its invocation list has just two entries but it invokes the three methods `M1`, `M2`, and `M1`, in that order just as `cd4` does. -> +> > The structure of the invocation list affects delegate subtraction. Delegate `cd6`, created by subtracting `cd2` (which invokes `M2`) from `cd4` (which invokes `M1`, `M2`, and `M1`) invokes `M1` and `M1`. However delegate `td6`, created by subtracting `cd2` (which invokes `M2`) from `td4` (which invokes `M1`, `M2`, and `M1`) still invokes `M1`, `M2` and `M1`, in that order, as `M2` is not a single entry in the list but a member of a nested list. > For more examples of combining (as well as removing) delegates, see [§19.6](delegates.md#196-delegate-invocation). *end example* -Once instantiated, a delegate instance always refers to the same invocation list. +Once instantiated, a delegate instance always refers to the same invocation list. > *Note*: Remember, when two delegates are combined, or one is removed from another, a new delegate results with its own invocation list; the invocation lists of the delegates combined or removed remain unchanged. *end note* @@ -227,7 +227,7 @@ Invocation of a delegate instance whose invocation list contains multiple entrie Attempting to invoke a delegate instance whose value is `null` results in an exception of type `System.NullReferenceException`. > *Example*: The following example shows how to instantiate, combine, remove, and invoke delegates: -> +> > ```csharp > using System; > @@ -273,9 +273,9 @@ Attempting to invoke a delegate instance whose value is `null` results in an exc > } > ``` > As shown in the statement `cd3 += cd1;`, a delegate can be present in an invocation list multiple times. In this case, it is simply invoked once per occurrence. In an invocation list such as this, when that delegate is removed, the last occurrence in the invocation list is the one actually removed. -> +> > Immediately prior to the execution of the final statement, `cd3 -= cd1`;, the delegate `cd3` refers to an empty invocation list. Attempting to remove a delegate from an empty list (or to remove a non-existent delegate from a non-empty list) is not an error. -> +> > The output produced is: > ```console > C.M1: -1 diff --git a/standard/enums.md b/standard/enums.md index 13044c561..b12f62a01 100644 --- a/standard/enums.md +++ b/standard/enums.md @@ -5,7 +5,7 @@ An ***enum type*** is a distinct value type ([§8.3](types.md#83-value-types)) that declares a set of named constants. > *Example:* The example -> +> > ```csharp > enum Color > { @@ -47,7 +47,7 @@ Each enum type has a corresponding integral type called the ***underlying type** An enum declaration that does not explicitly declare an underlying type has an underlying type of `int`. > *Example*: The example -> +> > ```csharp > enum Color: long > { diff --git a/standard/expressions.md b/standard/expressions.md index 0673b62ea..328dee67f 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -76,7 +76,7 @@ Static binding takes place at compile-time, whereas dynamic binding takes place > Console.WriteLine(d); // dynamic binding to Console.WriteLine(int) > ``` > The first two calls are statically bound: the overload of `Console.WriteLine` is picked based on the compile-time type of their argument. Thus, the binding-time is *compile-time*. -> +> > The third call is dynamically bound: the overload of `Console.WriteLine` is picked based on the run-time type of its argument. This happens because the argument is a dynamic expression – its compile-time type is dynamic. Thus, the binding-time for the third call is *run-time*. *end example* ### 11.3.3 Dynamic binding @@ -150,9 +150,9 @@ The precedence of an operator is established by the definition of its associated > [§11.14](expressions.md#1114-the-null-coalescing-operator) | Null coalescing | `??` > [§11.15](expressions.md#1115-conditional-operator) | Conditional | `?:` > [§11.18](expressions.md#1118-assignment-operators) and [§11.16](expressions.md#1116-anonymous-function-expressions) | Assignment and lambda expression | `=` `*=` `/=` `%=` `+=` `-=` `<<=` `>>=` `&=` `^=` `\|=` `=>` -> -> *end note* - +> +> *end note* + When an operand occurs between two operators with the same precedence, the ***associativity*** of the operators controls the order in which the operations are performed: - Except for the assignment operators and the null coalescing operator, all binary operators are ***left-associative***, meaning that operations are performed from left to right. @@ -190,7 +190,7 @@ When a binary operator is overloaded, the corresponding compound assignment oper The assignment operator itself `(=)` cannot be overloaded. An assignment always performs a simple store of a value into a variable ([§11.18.2](expressions.md#11182-simple-assignment)). -Cast operations, such as `(T)x`, are overloaded by providing user-defined conversions ([§10.5](conversions.md#105-user-defined-conversions)). +Cast operations, such as `(T)x`, are overloaded by providing user-defined conversions ([§10.5](conversions.md#105-user-defined-conversions)). > *Note*: User-defined conversions do not affect the behavior of the `is` or `as` operators. *end note* @@ -366,7 +366,7 @@ For purposes of member lookup, a type `T` is considered to have the following b - If `T` is `object` or `dynamic`, then `T` has no base type. - If `T` is an *enum_type*, the base types of `T` are the class types `System.Enum`, `System.ValueType`, and `object`. -- If `T` is a *struct_type*, the base types of `T` are the class types `System.ValueType` and `object`. +- If `T` is a *struct_type*, the base types of `T` are the class types `System.ValueType` and `object`. > *Note*: A *nullable_value_type* is a *struct_type* ([§8.3.1](types.md#831-general)). *end note* - If `T` is a *class_type*, the base types of `T` are the base classes of `T`, including the class type `object`. - If `T` is an *interface_type*, the base types of `T` are the base interfaces of `T` and the class type `object`. @@ -404,7 +404,7 @@ Once a particular function member has been identified at binding-time, possibly - + @@ -638,7 +638,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. > *Note*: Because these are always constant, their evaluation will not impact the evaluation of the remaining arguments. *end note* @@ -840,7 +840,7 @@ The ***inferred return type*** is determined as follows: > Sequence.Select(customers, (Customer c) => c.Name) > ``` > and the result is of type `IEnumerable`. -> +> > The following example demonstrates how anonymous function type inference allows type information to “flow” between arguments in a generic method invocation. Given the method: > ```csharp > static Z F(X value, Func f1, Func f2) @@ -1072,12 +1072,12 @@ The result of the invocation of an instance constructor ([§11.7.15.2](expressio A function member implemented in a *value_type* can be invoked through a boxed instance of that *value_type* in the following situations: -- When the function member is an override of a method inherited from type *class_type* and is invoked through an instance expression of that *class_type*. +- When the function member is an override of a method inherited from type *class_type* and is invoked through an instance expression of that *class_type*. > *Note*: The *class_type* will always be one of `System.Object`, `System.ValueType` or `System.Enum`. *end note* - When the function member is an implementation of an interface function member and is invoked through an instance expression of an *interface_type*. - When the function member is invoked through a delegate. -In these situations, the boxed instance is considered to contain a variable of the *value_type*, and this variable becomes the variable referenced by this within the function member invocation. +In these situations, the boxed instance is considered to contain a variable of the *value_type*, and this variable becomes the variable referenced by this within the function member invocation. > *Note*: In particular, this means that when a function member is invoked on a boxed instance, it is possible for the function member to modify the value contained in the boxed instance. *end note* @@ -1288,7 +1288,7 @@ In an *interpolation_minimum_width* the *constant_expression* shall have an impl - If the alignment is positive the formatted string is right-aligned by prepending the padding, - Otherwise it is left-aligned by appending the padding. -The overall meaning of an *interpolated_string_expression*, including the above formatting and padding of interpolations, is defined by a conversion of the expression to a method invocation: if the type of the expression is `System.IFormattable` or `System.FormattableString` that method is `System.Runtime.CompilerServices.FormattableStringFactory.Create` ([§C.3](standard-library.md#c3-standard-library-types-not-defined-in-isoiec-23271)) which returns a value of type `System.FormattableString`; otherwise the type must be `string` and the method is `string.Format` ([§C.2](standard-library.md#c2-standard-library-types-defined-in-isoiec-23271)) which returns a value of type `string`. +The overall meaning of an *interpolated_string_expression*, including the above formatting and padding of interpolations, is defined by a conversion of the expression to a method invocation: if the type of the expression is `System.IFormattable` or `System.FormattableString` that method is `System.Runtime.CompilerServices.FormattableStringFactory.Create` ([§C.3](standard-library.md#c3-standard-library-types-not-defined-in-isoiec-23271)) which returns a value of type `System.FormattableString`; otherwise the type must be `string` and the method is `string.Format` ([§C.2](standard-library.md#c2-standard-library-types-defined-in-isoiec-23271)) which returns a value of type `string`. In both cases, the argument list of the call consists of a *format string literal* with *format specifications* for each interpolation, and an argument for each expression corresponding to the format specifications. @@ -1450,10 +1450,10 @@ The *member_access* is evaluated and classified as follows: #### 11.7.6.2 Identical simple names and type names -In a member access of the form `E.I`, if `E` is a single identifier, and if the meaning of `E` as a *simple_name* ([§11.7.4](expressions.md#1174-simple-names)) is a constant, field, property, local variable, or parameter with the same type as the meaning of `E` as a *type_name* ([§7.8.1](basic-concepts.md#781-general)), then both possible meanings of `E` are permitted. The member lookup of `E.I` is never ambiguous, since `I` shall necessarily be a member of the type `E` in both cases. In other words, the rule simply permits access to the static members and nested types of `E` where a compile-time error would otherwise have occurred. +In a member access of the form `E.I`, if `E` is a single identifier, and if the meaning of `E` as a *simple_name* ([§11.7.4](expressions.md#1174-simple-names)) is a constant, field, property, local variable, or parameter with the same type as the meaning of `E` as a *type_name* ([§7.8.1](basic-concepts.md#781-general)), then both possible meanings of `E` are permitted. The member lookup of `E.I` is never ambiguous, since `I` shall necessarily be a member of the type `E` in both cases. In other words, the rule simply permits access to the static members and nested types of `E` where a compile-time error would otherwise have occurred. > *Example*: -> +> > ```csharp > struct Color > { @@ -1618,7 +1618,7 @@ The search for `C` proceeds as follows: - Otherwise, overload resolution is applied to the candidate set as described in [§11.6.4](expressions.md#1164-overload-resolution). If no single best method is found, a compile-time error occurs. - `C` is the type within which the best method is declared as an extension method. -Using `C` as a target, the method call is then processed as a static method invocation ([§11.6.6](expressions.md#1166-function-member-invocation)). +Using `C` as a target, the method call is then processed as a static method invocation ([§11.6.6](expressions.md#1166-function-member-invocation)). > *Note*: Unlike an instance method invocation, no exception is thrown when *expr* evaluates to a null reference. Instead, this `null` value is passed to the extension method as it would be via a regular static method invocation. It is up to the extension method implementation to decide how to respond to such a call. *end note* @@ -1695,7 +1695,7 @@ The preceding rules mean that instance methods take precedence over extension me > } > } > ``` -> +> > The output of this example is: > ```console > E.F(1) @@ -2080,7 +2080,7 @@ When an initializer target refers to an indexer, the arguments to the indexer sh > Rectangle r = __r; > ``` > where `__r`, `__p1` and `__p2` are temporary variables that are otherwise invisible and inaccessible. -> +> > If `Rectangle`’s constructor allocates the two embedded `Point` instances > ```csharp > public class Rectangle @@ -2315,7 +2315,7 @@ The run-time processing of a *delegate_creation_expression* of the form new `D(E - A new instance of the delegate type `D` is allocated. If there is not enough memory available to allocate the new instance, a `System.OutOfMemoryException` is thrown and no further steps are executed. - The new delegate instance is initialized with a single-entry invocation list that invokes `E`. -The invocation list of a delegate is determined when the delegate is instantiated and then remains constant for the entire lifetime of the delegate. In other words, it is not possible to change the target callable entities of a delegate once it has been created. +The invocation list of a delegate is determined when the delegate is instantiated and then remains constant for the entire lifetime of the delegate. In other words, it is not possible to change the target callable entities of a delegate once it has been created. > *Note*: Remember, when two delegates are combined or one is removed from another, a new delegate results; no existing delegate has its content changed. *end note* @@ -2448,7 +2448,7 @@ comma The first form of *typeof_expression* consists of a `typeof` keyword followed by a parenthesized type. The result of an expression of this form is the `System.Type` object for the indicated type. There is only one `System.Type` object for any given type. This means that for a type `T`, `typeof(T) == typeof(T)` is always true. The type cannot be `dynamic`. -The second form of *typeof_expression* consists of a `typeof` keyword followed by a parenthesized *unbound_type_name*. +The second form of *typeof_expression* consists of a `typeof` keyword followed by a parenthesized *unbound_type_name*. > *Note*: An *unbound_type_name* is very similar to a *type_name* ([§7.8](basic-concepts.md#78-namespace-and-type-names)) except that an *unbound_type_name* contains *generic_dimension_specifier*s where a *type_name* contains *type_argument_list*s. *end note* @@ -2460,7 +2460,7 @@ When the operand of a *typeof_expression* is a sequence of tokens that satisfies The result of the *typeof_expression* is the `System.Type` object for the resulting unbound generic type. -The third form of *typeof_expression* consists of a `typeof` keyword followed by a parenthesized `void` keyword. The result of an expression of this form is the `System.Type` object that represents the absence of a type. The type object returned by `typeof(void)` is distinct from the type object returned for any type. +The third form of *typeof_expression* consists of a `typeof` keyword followed by a parenthesized `void` keyword. The result of an expression of this form is the `System.Type` object that represents the absence of a type. The type object returned by `typeof(void)` is distinct from the type object returned for any type. > *Note*: This special type `object` is useful in class libraries that allow reflection onto methods in the language, where those methods wish to have a way to represent the return type of any method, including `void` methods, with an instance of `System.Type`. *end note* @@ -3527,7 +3527,7 @@ The predefined addition operators are listed below. For numeric and enumeration ```csharp D operator +(D x, D y); ``` - If the first operand is `null`, the result of the operation is the value of the second operand (even if that is also `null`). Otherwise, if the second operand is `null`, then the result of the operation is the value of the first operand. Otherwise, the result of the operation is a new delegate instance whose invocation list consists of the elements in the invocation list of the first operand, followed by the elements in the invocation list of the second operand. That is, the invocation list of the resulting delegate is the concatenation of the invocation lists of the two operands. + If the first operand is `null`, the result of the operation is the value of the second operand (even if that is also `null`). Otherwise, if the second operand is `null`, then the result of the operation is the value of the first operand. Otherwise, the result of the operation is a new delegate instance whose invocation list consists of the elements in the invocation list of the first operand, followed by the elements in the invocation list of the second operand. That is, the invocation list of the resulting delegate is the concatenation of the invocation lists of the two operands. > *Note*: For examples of delegate combination, see [§11.9.6](expressions.md#1196-subtraction-operator) and [§19.6](delegates.md#196-delegate-invocation). Since `System.Delegate` is not a delegate type, operator + is not defined for it. *end note* @@ -3956,7 +3956,7 @@ In addition to normal applicability rules ([§11.6.4.2](expressions.md#11642-app Unless one of these conditions is true, a binding-time error occurs. > *Note*: Notable implications of these rules are: -> +> > - It is a binding-time error to use the predefined reference type equality operators to compare two references that are known to be different at binding-time. For example, if the binding-time types of the operands are two class types, and if neither derives from the other, then it would be impossible for the two operands to reference the same object. Thus, the operation is considered a binding-time error. > - The predefined reference type equality operators do not permit value type operands to be compared (except when type parameters are compared to `null`, which is handled specially). > - Operands of predefined reference type equality operators are never boxed. It would be meaningless to perform such boxing operations, since references to the newly allocated boxed instances would necessarily differ from all other references. @@ -3979,7 +3979,7 @@ Unless one of these conditions is true, a binding-time error occurs. > ``` > The `x == null` construct is permitted even though `T` could represent a non-nullable value type, and the result is simply defined to be `false` when `T` is a non-nullable value type. *end example* -For an operation of the form `x == y` or `x != y`, if any applicable `operator ==` or `operator !=` exists, the operator overload resolution ([§11.4.5](expressions.md#1145-binary-operator-overload-resolution)) rules will select that operator instead of the predefined reference type equality operator. +For an operation of the form `x == y` or `x != y`, if any applicable `operator ==` or `operator !=` exists, the operator overload resolution ([§11.4.5](expressions.md#1145-binary-operator-overload-resolution)) rules will select that operator instead of the predefined reference type equality operator. > *Note*: It is always possible to select the predefined reference type equality operator by explicitly casting both of the operands to type `object`. *end note* @@ -4007,7 +4007,7 @@ For an operation of the form `x == y` or `x != y`, if any applicable `operat > False > ``` > The `s` and `t` variables refer to two distinct string instances containing the same characters. The first comparison outputs `True` because the predefined string equality operator ([§11.11.8](expressions.md#11118-string-equality-operators)) is selected when both operands are of type `string`. The remaining comparisons all output `False` because the overload of `operator ==` in the `string` type is not applicable when either operand has a binding-time type of `object`. -> +> > Note that the above technique is not meaningful for value types. The example > ```csharp > class Test @@ -4036,7 +4036,7 @@ Two `string` values are considered equal when one of the following is true: - Both values are `null`. - Both values are non-`null` references to string instances that have identical lengths and identical characters in each character position. -The string equality operators compare string values rather than string references. When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. +The string equality operators compare string values rather than string references. When two separate string instances contain the exact same sequence of characters, the values of the strings are equal, but the references are different. > *Note*: As described in [§11.11.7](expressions.md#11117-reference-type-equality-operators), the reference type equality operators can be used to compare string references instead of string values. *end note* @@ -4554,7 +4554,7 @@ Anonymous functions in an argument list participate in type inference and overlo > } > ``` > The `ItemList` class has two `Sum` methods. Each takes a `selector` argument, which extracts the value to sum over from a list item. The extracted value can be either an `int` or a `double` and the resulting sum is likewise either an `int` or a `double`. -> +> > The `Sum` methods could for example be used to compute sums from a list of detail lines in an order. > ```csharp > class Detail @@ -4573,7 +4573,7 @@ Anonymous functions in an argument list participate in type inference and overlo > } > ``` > In the first invocation of `orderDetails.Sum`, both `Sum` methods are applicable because the anonymous function `d => d.UnitCount` is compatible with both `Func` and `Func`. However, overload resolution picks the first `Sum` method because the conversion to `Func` is better than the conversion to `Func`. -> +> > In the second invocation of `orderDetails.Sum`, only the second `Sum` method is applicable because the anonymous function `d => d.UnitPrice * d.UnitCount` produces a value of type `double`. Thus, overload resolution picks the second `Sum` method for that invocation. *end example* ### 11.16.5 Anonymous functions and dynamic binding @@ -5047,8 +5047,7 @@ query_continuation ; ``` -A query expression begins with a `from` clause and ends with either a `select` or `group` clause. The initial `from` clause may be followed by zero or more `from`, `let`, `where`, `join` or `orderby` clauses. Each `from` clause is a generator introducing a ***range variable*** that ranges over the elements of a ***sequence***. Each `let` clause introduces a range variable representing a value computed by means of previous range variables. Each `where` clause is a -filter that excludes items from the result. Each `join` clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. Each `orderby` clause reorders items according to specified criteria.The final `select` or `group` clause specifies the shape of the result in terms of the range variables. Finally, an `into` clause can be used to “splice” queries by treating the results of one query as a generator in a subsequent query. +A query expression begins with a `from` clause and ends with either a `select` or `group` clause. The initial `from` clause may be followed by zero or more `from`, `let`, `where`, `join` or `orderby` clauses. Each `from` clause is a generator introducing a ***range variable*** that ranges over the elements of a ***sequence***. Each `let` clause introduces a range variable representing a value computed by means of previous range variables. Each `where` clause is a filter that excludes items from the result. Each `join` clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. Each `orderby` clause reorders items according to specified criteria.The final `select` or `group` clause specifies the shape of the result in terms of the range variables. Finally, an `into` clause can be used to “splice” queries by treating the results of one query as a generator in a subsequent query. ### 11.17.2 Ambiguities in query expressions @@ -5554,7 +5553,7 @@ In the translation steps described above, transparent identifiers are always int > .Select(x => new { x.c.Name, x.o.Total }) > ``` > where `x` is a compiler generated identifier that is otherwise invisible and inaccessible. -> +> > The example > ```csharp > from c in customers diff --git a/standard/foreword.md b/standard/foreword.md index 65a914834..0563c8b0d 100644 --- a/standard/foreword.md +++ b/standard/foreword.md @@ -7,7 +7,7 @@ This specification replaces ECMA-334:2017. Changes from the previous edition inc - Exception filters - Expression-bodied function members - Extension Add methods in collection initializers -- Improved overload resolution +- Improved overload resolution - Initialization of an accessible indexer - Initialization of associative collections using indexers - Interpolated strings diff --git a/standard/interfaces.md b/standard/interfaces.md index 6038b947e..7285dc778 100644 --- a/standard/interfaces.md +++ b/standard/interfaces.md @@ -12,7 +12,7 @@ Interfaces can contain methods, properties, events, and indexers. The interface An *interface_declaration* is a *type_declaration* ([§13.7](namespaces.md#137-type-declarations)) that declares a new interface type. -```ANTLR +```ANTLR interface_declaration : attributes? interface_modifier* 'partial'? 'interface' identifier variant_type_parameter_list? interface_base? @@ -137,7 +137,7 @@ The explicit base interfaces can be constructed interface types ([§8.4](types.m For a constructed interface type, the explicit base interfaces are formed by taking the explicit base interface declarations on the generic type declaration, and substituting, for each *type_parameter* in the base interface declaration, the corresponding *type_argument* of the constructed type. -The explicit base interfaces of an interface shall be at least as accessible as the interface itself ([§7.5.5](basic-concepts.md#755-accessibility-constraints)). +The explicit base interfaces of an interface shall be at least as accessible as the interface itself ([§7.5.5](basic-concepts.md#755-accessibility-constraints)). > *Note*: For example, it is a compile-time error to specify a `private` or `internal` interface in the *interface_base* of a `public` interface. *end note* @@ -249,7 +249,7 @@ All formal parameter types of an interface method shall be input-safe ([§17.2.3 > *Note*: Output parameters are required to be input-safe due to common implementation restrictions. *end note* -Furthermore, each class type constraint, interface type constraint and type parameter constraint on any type parameters of the method shall be input-safe. +Furthermore, each class type constraint, interface type constraint and type parameter constraint on any type parameters of the method shall be input-safe. Furthermore, each class type constraint, interface type constraint and type parameter constraint on any type parameter of the method shall be input-safe. @@ -263,7 +263,7 @@ These rules ensure that any covariant or contravariant usage of the interface re > } > ``` > is ill-formed because the usage of `T` as a type parameter constraint on `U` is not input-safe. -> +> > Were this restriction not in place it would be possible to violate type safety in the following manner: > ```csharp > class B {} @@ -347,7 +347,7 @@ Interface members are accessed through member access ([§11.7.6](expressions.md# For interfaces that are strictly single-inheritance (each interface in the inheritance chain has exactly zero or one direct base interface), the effects of the member lookup ([§11.5](expressions.md#115-member-lookup)), method invocation ([§11.7.8.2](expressions.md#11782-method-invocations)), and indexer access ([§11.7.10.3](expressions.md#117103-indexer-access)) rules are exactly the same as for classes and structs: More derived members hide less derived members with the same name or signature. However, for multiple-inheritance interfaces, ambiguities can occur when two or more unrelated base interfaces declare members with the same name or signature. This subclause shows several examples, some of which lead to ambiguities and others which don’t. In all cases, explicit casts can be used to resolve the ambiguities. > *Example*: In the following code -> +> > ```csharp > interface IList > { @@ -432,7 +432,7 @@ For interfaces that are strictly single-inheritance (each interface in the inher > } > ``` > the `IBase.F` member is hidden by the `ILeft.F` member. The invocation `d.F(1)` thus selects `ILeft.F`, even though `IBase.F` appears to not be hidden in the access path that leads through `IRight`. -> +> > The intuitive rule for hiding in multiple-inheritance interfaces is simply this: If a member is hidden in any access path, it is hidden in all access paths. Because the access path from `IDerived` to `ILeft` to `IBase` hides `IBase.F`, the member is also hidden in the access path from `IDerived` to `IRight` to `IBase`. *end example* ## 17.5 Qualified interface member names diff --git a/standard/lexical-structure.md b/standard/lexical-structure.md index 247e08621..587ffddcf 100644 --- a/standard/lexical-structure.md +++ b/standard/lexical-structure.md @@ -32,7 +32,7 @@ While the ANTLR notation is used, this Standard does not present a complete ANTL ANTLR distinguishes between lexical and syntactic, termed parser by ANTLR, grammars in its notation by starting lexical rules with an uppercase letter and parser rules with a lowercase letter. -> *Note*: The C# lexical grammar ([§6.2.3](lexical-structure.md#623-lexical-grammar)) and syntactic grammar ([§6.2.4](lexical-structure.md#624-syntactic-grammar)) are not in exact correspondence with the ANTLR division into lexical and parser grammers. This small mismatch means that some ANTLR parser rules are used when specifying the C# lexical grammar. *end note* +> *Note*: The C# lexical grammar ([§6.2.3](lexical-structure.md#623-lexical-grammar)) and syntactic grammar ([§6.2.4](lexical-structure.md#624-syntactic-grammar)) are not in exact correspondence with the ANTLR division into lexical and parser grammers. This small mismatch means that some ANTLR parser rules are used when specifying the C# lexical grammar. *end note* ### 6.2.3 Lexical grammar @@ -53,7 +53,7 @@ Every compilation unit in a C# program shall conform to the *compilation_unit* The productions for *simple_name* ([§11.7.4](expressions.md#1174-simple-names)) and *member_access* ([§11.7.6](expressions.md#1176-member-access)) can give rise to ambiguities in the grammar for expressions. > *Example*: The statement: -> +> > ```csharp > F(G(7)); > ``` @@ -158,7 +158,7 @@ New_Line For compatibility with source code editing tools that add end-of-file markers, and to enable a compilation unit to be viewed as a sequence of properly terminated lines, the following transformations are applied, in order, to every compilation unit in a C# program: - If the last character of the compilation unit is a Control-Z character (U+001A), this character is deleted. -- A carriage-return character (U+000D) is added to the end of the compilation unit if that compilation unit is non-empty and if the last character of the compilation unit is not a carriage return (U+000D), a line feed (U+000A), a next line character (U+0085), a line separator (U+2028), or a paragraph separator (U+2029). +- A carriage-return character (U+000D) is added to the end of the compilation unit if that compilation unit is non-empty and if the last character of the compilation unit is not a carriage return (U+000D), a line feed (U+000A), a next line character (U+0085), a line separator (U+2028), or a paragraph separator (U+2029). > *Note*: The additional carriage-return allows a program to end in a *PP_Directive* ([§6.5](lexical-structure.md#65-pre-processing-directives)) that does not have a terminating *New_Line*. *end note* @@ -246,11 +246,11 @@ Comments are not processed within character and string literals. > // B */ C(); > ``` > is not actually a single-line comment, since `//` has no special meaning within a delimited comment, and so `*/` does have its usual special meaning in that line. -> +> > Likewise, the delimited comment starting before `D` ends before `E`. The reason is that `"D */ "` is not actually a string literal, since it appears inside a delimited comment. -> +> > A useful consequence of `/*` and `*/` having no special meaning within a single-line comment is that a block of source code lines can be commented out by putting `//` at the beginning of each line. In general it does not work to put `/*` before those lines and `*/` after them, as this does not properly encapsulate delimited comments in the block, and in general may completely change the structure of such delimited comments. -> +> > Example code: > ```csharp > static void Main() @@ -442,7 +442,7 @@ fragment Formatting_Character An identifier in a conforming program shall be in the canonical format defined by Unicode Normalization Form C, as defined by Unicode Standard Annex 15. The behavior when encountering an identifier not in Normalization Form C is implementation-defined; however, a diagnostic is not required. -The prefix “`@`” enables the use of keywords as identifiers, which is useful when interfacing with other programming languages. The character `@` is not actually part of the identifier, so the identifier might be seen in other languages as a normal identifier, without the prefix. An identifier with an `@` prefix is called a ***verbatim identifier***. +The prefix “`@`” enables the use of keywords as identifiers, which is useful when interfacing with other programming languages. The character `@` is not actually part of the identifier, so the identifier might be seen in other languages as a normal identifier, without the prefix. An identifier with an `@` prefix is called a ***verbatim identifier***. > *Note*: Use of the `@` prefix for identifiers that are not keywords is permitted, but strongly discouraged as a matter of style. *end note* @@ -552,7 +552,6 @@ literal > *Note*: *literal* is a parser rule as it groups other token kinds and does not introduce a new token kind. *end note* - #### 6.4.5.2 Boolean literals There are two Boolean literal values: `true` and `false`. @@ -638,7 +637,7 @@ fragment Sign fragment Real_Type_Suffix : 'F' | 'f' | 'D' | 'd' | 'M' | 'm' ; -``` +``` If no *Real_Type_Suffix* is specified, the type of the *Real_Literal* is `double`. Otherwise, the *Real_Type_Suffix* determines the type of the real literal, as follows: @@ -648,7 +647,7 @@ If no *Real_Type_Suffix* is specified, the type of the *Real_Literal* is `double > *Example*: The literals `1d`, `1.5d`, `1e10d`, and `123.456D` are all of type `double`. *end example* - A real literal suffixed by `M` or `m` is of type `decimal`. > *Example*: The literals `1m`, `1.5m`, `1e10m`, and `123.456M` are all of type `decimal`. *end example* - This literal is converted to a `decimal` value by taking the exact value, and, if necessary, rounding to the nearest representable value using banker’s rounding ([§8.3.8](types.md#838-the-decimal-type)). Any scale apparent in the literal is preserved unless the value is rounded. + This literal is converted to a `decimal` value by taking the exact value, and, if necessary, rounding to the nearest representable value using banker’s rounding ([§8.3.8](types.md#838-the-decimal-type)). Any scale apparent in the literal is preserved unless the value is rounded. > *Note*: Hence, the literal `2.900m` will be parsed to form the `decimal` with sign `0`, coefficient `2900`, and scale `3`. *end note* If the magnitude of the specified literal is too large to be represented in the indicated type, a compile-time error occurs. @@ -707,17 +706,17 @@ A simple escape sequence represents a Unicode character, as described in the tab | __Escape sequence__ | __Character name__ | __Unicode code point__ | |---------------------|--------------------|----------------------| -| `\'` | Single quote | U+0027 | -| `\"` | Double quote | U+0022 | -| `\\` | Backslash | U+005C | -| `\0` | Null | U+0000 | -| `\a` | Alert | U+0007 | -| `\b` | Backspace | U+0008 | -| `\f` | Form feed | U+000C | -| `\n` | New line | U+000A | -| `\r` | Carriage return | U+000D | -| `\t` | Horizontal tab | U+0009 | -| `\v` | Vertical tab | U+000B | +| `\'` | Single quote | U+0027 | +| `\"` | Double quote | U+0022 | +| `\\` | Backslash | U+005C | +| `\0` | Null | U+0000 | +| `\a` | Alert | U+0007 | +| `\b` | Backspace | U+0008 | +| `\f` | Form feed | U+000C | +| `\n` | New line | U+000A | +| `\r` | Carriage return | U+000D | +| `\t` | Horizontal tab | U+0009 | +| `\v` | Vertical tab | U+000B | The type of a *Character_Literal* is `char`. @@ -849,7 +848,7 @@ right_shift_assignment > *Note*: *right_shift* and *right_shift_assignment* are parser rules as they do not introduce a new token kind but represent a sequence of two tokens. The *operator_or_punctuator* rule exists for descriptive purposes only and is not used elsewhere in the grammar. *end note* -*right_shift* is made up of the two tokens `>` and `>`. Similarly, *right_shift_assignment* is made up of the two tokens `>` and `>=`. Unlike other productions in the syntactic grammar, no characters of any kind (not even whitespace) are allowed between the two tokens in each of these productions. These productions are treated specially in order to enable the correct handling of *type_parameter_lists* ([§14.2.3](classes.md#1423-type-parameters)). +*right_shift* is made up of the two tokens `>` and `>`. Similarly, *right_shift_assignment* is made up of the two tokens `>` and `>=`. Unlike other productions in the syntactic grammar, no characters of any kind (not even whitespace) are allowed between the two tokens in each of these productions. These productions are treated specially in order to enable the correct handling of *type_parameter_lists* ([§14.2.3](classes.md#1423-type-parameters)). > *Note*: Prior to the addition of generics to C#, `>>` and `>>=` were both single tokens. However, the syntax for generics uses the `<` and `>` characters to delimit type parameters and type arguments. It is often desirable to use nested constructed types, such as `List>`. Rather than requiring the programmer to separate the `>` and `>` by a space, the definition of the two *operator_or_punctuator*s was changed. @@ -1164,7 +1163,7 @@ Any remaining conditional sections are skipped and no tokens, except those for p > } > ``` > Note, however, that pre-processing directives are required to be lexically correct even in skipped sections of source code. -> +> > Pre-processing directives are not processed when they appear inside multi-line input elements. For example, the program: > ```csharp > class Hello diff --git a/standard/namespaces.md b/standard/namespaces.md index 48063d049..feefaa9da 100644 --- a/standard/namespaces.md +++ b/standard/namespaces.md @@ -740,9 +740,9 @@ Using this notation, the meaning of a *qualified_alias_member* is determined as > global::A y; // Valid: References A in the global namespace > } > ``` -> +> > using `global.A` causes a compile-time error since there is no entity named `global` in scope. If some entity named global were in scope, then `global` in `global.A` would have resolved to that entity. -> +> > Using `global` as the left-hand identifier of a *qualified_alias_member* always causes a lookup in the `global` namespace, even if there is a using alias named `global`. In the code: > ```csharp > using global = MyGlobalTypes; diff --git a/standard/standard-library.md b/standard/standard-library.md index e59cc662a..f1971affc 100644 --- a/standard/standard-library.md +++ b/standard/standard-library.md @@ -452,8 +452,7 @@ it is converted to a string. Either standard or custom formats can be used. A standard format takes the form *Axx*, where *A* is a single alphabetic character called the *format specifier*, and *xx* is an integer between zero and 99 inclusive, called the *precision specifier*. The format specifier controls the type of formatting applied to the value being represented as a string. The -*precision specifier* controls the number -of significant digits or decimal places in the string, if applicable. +*precision specifier* controls the number of significant digits or decimal places in the string, if applicable. > *Note:* For the list of standard format specifiers, see the table below. Note that a given data type, such as `System.Int32`, might not support one or more of the standard format specifiers. *end note* @@ -516,7 +515,7 @@ property.

is omitted, six decimal places are included in the string.

The exponent -(+/-xxx) +(+/-xxx) consists of either a positive or negative number symbol followed by a minimum of three digits (xxx). The exponent is left-padded with zeros, if necessary. The case of the format specifier @@ -540,8 +539,7 @@ supplied by the System.Globalization.NumberFormatInfo.NegativeSign property.

The precision specifier determines the number of decimal places (dd...d) in the string. If the precision specifier is omitted, -System.Globalization.NumberFormatInfo.NumberDecimalDigits determines the number of decimal -places in the string. Results are rounded to the nearest representable +System.Globalization.NumberFormatInfo.NumberDecimalDigits determines the number of decimal places in the string. Results are rounded to the nearest representable value when necessary.

@@ -646,8 +644,7 @@ letters are used in the hexadecimal representation.
ConstructExampleExample Description
If the numerical value is a `System.Single` or `System.Double` with a value of `NaN`, -`PositiveInfinity`, or `NegativeInfinity`, the format -specifier is ignored, and one of the following is returned: `System.Globalization.NumberFormatInfo.NaNSymbol`, `System.Globalization.NumberFormatInfo.PositiveInfinitySymbol`, or `System.Globalization.NumberFormatInfo.NegativeInfinitySymbol`. +`PositiveInfinity`, or `NegativeInfinity`, the format specifier is ignored, and one of the following is returned: `System.Globalization.NumberFormatInfo.NaNSymbol`, `System.Globalization.NumberFormatInfo.PositiveInfinitySymbol`, or `System.Globalization.NumberFormatInfo.NegativeInfinitySymbol`. A custom format is any string specified as a format that is not in the form of a standard format string (Axx) described above. The diff --git a/standard/statements.md b/standard/statements.md index 7fd80c027..73de075f6 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -2,7 +2,7 @@ ## 12.1 General -C# provides a variety of statements. +C# provides a variety of statements. > *Note*: Most of these statements will be familiar to developers who have programmed in C and C++. *end note* @@ -31,7 +31,7 @@ embedded_statement ; ``` *unsafe_statement* ([§22.2](unsafe-code.md#222-unsafe-contexts)) and *fixed_statement* ([§22.7](unsafe-code.md#227-the-fixed-statement)) are only available in unsafe code ([§22](unsafe-code.md#22-unsafe-code)). - + The *embedded_statement* nonterminal is used for statements that appear within other statements. The use of *embedded_statement* rather than *statement* excludes the use of declaration statements and labeled statements in these contexts. > *Example*: The code @@ -68,7 +68,7 @@ If a statement can possibly be reached by execution, the statement is said to be A warning is reported if a statement other than *throw_statement*, *block*, or *empty_statement* is unreachable. It is specifically not an error for a statement to be unreachable. > *Note*: To determine whether a particular statement or end point is reachable, the compiler performs flow analysis according to the reachability rules defined for each statement. The flow analysis takes into account the values of constant expressions ([§11.20](expressions.md#1120-constant-expressions)) that control the behavior of statements, but the possible values of non-constant expressions are not considered. In other words, for purposes of control flow analysis, a non-constant expression of a given type is considered to have any possible value of that type. -> +> > In the example > ```csharp > void F() @@ -214,7 +214,7 @@ labeled_statement A labeled statement declares a label with the name given by the *identifier*. The scope of a label is the whole block in which the label is declared, including any nested blocks. It is a compile-time error for two labels with the same name to have overlapping scopes. -A label can be referenced from `goto` statements ([§12.10.4](statements.md#12104-the-goto-statement)) within the scope of the label. +A label can be referenced from `goto` statements ([§12.10.4](statements.md#12104-the-goto-statement)) within the scope of the label. > *Note*: This means that `goto` statements can transfer control within blocks and out of blocks, but never into blocks. *end note* @@ -399,7 +399,7 @@ statement_expression ; ``` -Not all expressions are permitted as statements. +Not all expressions are permitted as statements. > *Note*: In particular, expressions such as `x + y` and `x == 1`, that merely compute a value (which will be discarded), are not permitted as statements. *end note* @@ -431,12 +431,12 @@ if_statement An `else` part is associated with the lexically nearest preceding `if` that is allowed by the syntax. > *Example*: Thus, an `if` statement of the form -> +> > ```csharp > if (x) if (y) F(); else G(); > ``` > is equivalent to -> +> > ```csharp > if (x) > { @@ -822,7 +822,7 @@ is then expanded to: } ``` -The variable `e` is not visible to or accessible to the expression `x` or the embedded statement or any other source code of the program. The variable `v` is read-only in the embedded statement. If there is not an explicit conversion ([§10.3](conversions.md#103-explicit-conversions)) from `T` (the iteration type) to `V` (the *local_variable_type* in the `foreach` statement), an error is produced and no further steps are taken. +The variable `e` is not visible to or accessible to the expression `x` or the embedded statement or any other source code of the program. The variable `v` is read-only in the embedded statement. If there is not an explicit conversion ([§10.3](conversions.md#103-explicit-conversions)) from `T` (the iteration type) to `V` (the *local_variable_type* in the `foreach` statement), an error is produced and no further steps are taken. > *Note*: If `x` has the value `null`, a `System.NullReferenceException` is thrown at run-time. *end note* @@ -1048,7 +1048,7 @@ goto_statement ; ``` -The target of a `goto` *identifier* statement is the labeled statement with the given label. If a label with the given name does not exist in the current function member, or if the `goto` statement is not within the scope of the label, a compile-time error occurs. +The target of a `goto` *identifier* statement is the labeled statement with the given label. If a label with the given name does not exist in the current function member, or if the `goto` statement is not within the scope of the label, a compile-time error occurs. > *Note*: This rule permits the use of a `goto` statement to transfer control *out of* a nested scope, but not *into* a nested scope. In the example > ```csharp diff --git a/standard/structs.md b/standard/structs.md index f4adf606a..7ec285f80 100644 --- a/standard/structs.md +++ b/standard/structs.md @@ -98,7 +98,7 @@ struct_member_declaration *fixed_size_buffer_declaration* ([§22.8.2](unsafe-code.md#2282-fixed-size-buffer-declarations)) is only available in unsafe code ([§22](unsafe-code.md#22-unsafe-code)). -> *Note*: All kinds of *class_member_declaration*s except *finalizer_declaration* are also *struct_member_declaration*s. *end note* +> *Note*: All kinds of *class_member_declaration*s except *finalizer_declaration* are also *struct_member_declaration*s. *end note* Except for the differences noted in [§15.4](structs.md#154-class-and-struct-differences), the descriptions of class members provided in [§14.3](classes.md#143-class-members) through [§14.12](classes.md#1412-static-constructors) apply to struct members as well. @@ -122,7 +122,7 @@ Structs differ from classes in several important ways: Structs are value types ([§8.3](types.md#83-value-types)) and are said to have value semantics. Classes, on the other hand, are reference types ([§8.2](types.md#82-reference-types)) and are said to have reference semantics. -A variable of a struct type directly contains the data of the struct, whereas a variable of a class type contains a reference to an object that contains the data. When a struct `B` contains an instance field of type `A` and `A` is a struct type, it is a compile-time error for `A` to depend on `B` or a type constructed from `B`. `A struct X` *directly depends on* a struct `Y` if `X` contains an instance field of type `Y`. Given this definition, the complete set of structs upon which a struct depends is the transitive closure of the *directly depends on* relationship. +A variable of a struct type directly contains the data of the struct, whereas a variable of a class type contains a reference to an object that contains the data. When a struct `B` contains an instance field of type `A` and `A` is a struct type, it is a compile-time error for `A` to depend on `B` or a type constructed from `B`. `A struct X` *directly depends on* a struct `Y` if `X` contains an instance field of type `Y`. Given this definition, the complete set of structs upon which a struct depends is the transitive closure of the *directly depends on* relationship. > *Example*: > ```csharp @@ -133,17 +133,17 @@ A variable of a struct type directly contains the data of the struct, whereas a > } > ``` > is an error because `Node` contains an instance field of its own type. Another example -> +> > ```csharp > struct A { B b; } > struct B { C c; } > struct C { A a; } > ``` -> -> is an error because each of the types `A`, `B`, and `C` depend on each other. +> +> is an error because each of the types `A`, `B`, and `C` depend on each other. *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.11](types.md#8311-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 `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.11](types.md#8311-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* @@ -225,7 +225,7 @@ The default value of a struct corresponds to the value returned by the default c A value of a class type can be converted to type `object` or to an interface type that is implemented by the class simply by treating the reference as another type at compile-time. Likewise, a value of type `object` or a value of an interface type can be converted back to a class type without changing the reference (but, of course, a run-time type check is required in this case). -Since structs are not reference types, these operations are implemented differently for struct types. When a value of a struct type is converted to certain reference types (as defined in [§10.2.9](conversions.md#1029-boxing-conversions)), a boxing operation takes place. Likewise, when a value of certain reference types (as defined in [§10.3.6](conversions.md#1036-unboxing-conversions)) is converted back to a struct type, an unboxing operation takes place. A key difference from the same operations on class types is that boxing and unboxing *copies* the struct value either into or out of the boxed instance. +Since structs are not reference types, these operations are implemented differently for struct types. When a value of a struct type is converted to certain reference types (as defined in [§10.2.9](conversions.md#1029-boxing-conversions)), a boxing operation takes place. Likewise, when a value of certain reference types (as defined in [§10.3.6](conversions.md#1036-unboxing-conversions)) is converted back to a struct type, an unboxing operation takes place. A key difference from the same operations on class types is that boxing and unboxing *copies* the struct value either into or out of the boxed instance. > *Note*: Thus, following a boxing or unboxing operation, changes made to the unboxed `struct` are not reflected in the boxed `struct`. *end note* @@ -233,7 +233,7 @@ For further details on boxing and unboxing, see [§10.2.9](conversions.md#1029-b ### 15.4.7 Meaning of this -The meaning of `this` in a struct differs from the meaning of `this` in a class, as described in [§11.7.12](expressions.md#11712-this-access). When a struct type overrides a virtual method inherited from `System.ValueType` (such as `Equals`, `GetHashCode`, or `ToString`), invocation of the virtual method through an instance of the struct type does not cause boxing to occur. This is true even when the struct is used as a type parameter and the invocation occurs through an instance of the type parameter type. +The meaning of `this` in a struct differs from the meaning of `this` in a class, as described in [§11.7.12](expressions.md#11712-this-access). When a struct type overrides a virtual method inherited from `System.ValueType` (such as `Equals`, `GetHashCode`, or `ToString`), invocation of the virtual method through an instance of the struct type does not cause boxing to occur. This is true even when the struct is used as a type parameter and the invocation occurs through an instance of the type parameter type. > *Example*: > ```csharp @@ -269,7 +269,7 @@ The meaning of `this` in a struct differs from the meaning of `this` in a class, > ``` > Although it is bad style for `ToString` to have side effects, the example demonstrates that no boxing occurred for the three invocations of `x.ToString()`. *end example* -Similarly, boxing never implicitly occurs when accessing a member on a constrained type parameter when the member is implemented within the value type. For example, suppose an interface `ICounter` contains a method `Increment`, which can be used to modify a value. If `ICounter` is used as a constraint, the implementation of the `Increment` method is called with a reference to the variable that `Increment` was called on, never a boxed copy. +Similarly, boxing never implicitly occurs when accessing a member on a constrained type parameter when the member is implemented within the value type. For example, suppose an interface `ICounter` contains a method `Increment`, which can be used to modify a value. If `ICounter` is used as a constraint, the implementation of the `Increment` method is called with a reference to the variable that `Increment` was called on, never a boxed copy. > *Example*: > ```csharp @@ -314,7 +314,7 @@ Similarly, boxing never implicitly occurs when accessing a member on a constrain ### 15.4.8 Field initializers -As described in [§15.4.5](structs.md#1545-default-values), the default value of a struct consists of the value that results from setting all value type fields to their default value and all reference type fields to `null`. For this reason, a struct does not permit instance field declarations to include variable initializers. This restriction applies only to instance fields. Static fields of a struct are permitted to include variable initializers. +As described in [§15.4.5](structs.md#1545-default-values), the default value of a struct consists of the value that results from setting all value type fields to their default value and all reference type fields to `null`. For this reason, a struct does not permit instance field declarations to include variable initializers. This restriction applies only to instance fields. Static fields of a struct are permitted to include variable initializers. > *Example*: The following > ```csharp @@ -328,7 +328,7 @@ As described in [§15.4.5](structs.md#1545-default-values), the default value of ### 15.4.9 Constructors -Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Instead, every struct implicitly has a parameterless instance constructor, which always returns the value that results from setting all value type fields to their default value and all reference type fields to `null` ([§8.3.3](types.md#833-default-constructors)). A struct can declare instance constructors having parameters. +Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Instead, every struct implicitly has a parameterless instance constructor, which always returns the value that results from setting all value type fields to their default value and all reference type fields to `null` ([§8.3.3](types.md#833-default-constructors)). A struct can declare instance constructors having parameters. > *Example*: > ```csharp @@ -407,6 +407,6 @@ Static constructors for structs follow most of the same rules as for classes. Th ### 15.4.11 Automatically implemented properties -Automatically implemented properties ([§14.7.4](classes.md#1474-automatically-implemented-properties)) use hidden backing fields, which are only accessible to the property accessors. +Automatically implemented properties ([§14.7.4](classes.md#1474-automatically-implemented-properties)) use hidden backing fields, which are only accessible to the property accessors. > *Note*: This access restriction means that constructors in structs containing automatically implemented properties often need an explicit constructor initializer where they would not otherwise need one, to satisfy the requirement of all fields being definitely assigned before any function member is invoked or the constructor returns. *end note* diff --git a/standard/types.md b/standard/types.md index 9fda0bba9..92ec38981 100644 --- a/standard/types.md +++ b/standard/types.md @@ -501,7 +501,7 @@ Whenever a constructed type or generic method is referenced, the supplied type a > *Note*: `System.ValueType` and `System.Enum` are reference types that satisfy this constraint. *end note* - `A` is a type parameter that is known to be a reference type ([§8.2](types.md#82-reference-types)). - If the constraint is the value type constraint (`struct`), the type `A` shall satisfy one of the following: - - `A` is a `struct` type or `enum` type, but not a nullable value type. + - `A` is a `struct` type or `enum` type, but not a nullable value type. > *Note*: `System.ValueType` and `System.Enum` are reference types that do not satisfy this constraint. *end note* - `A` is a type parameter having the value type constraint ([§14.2.5](classes.md#1425-type-parameter-constraints)). - If the constraint is the constructor constraint `new()`, the type `A` shall not be `abstract` and shall have a public parameterless constructor. This is satisfied if one of the following is true: diff --git a/standard/unsafe-code.md b/standard/unsafe-code.md index 27f6a94f1..cf32906d3 100644 --- a/standard/unsafe-code.md +++ b/standard/unsafe-code.md @@ -7,18 +7,18 @@ An implementation that does not support unsafe code is required to diagnose any **The remainder of this clause, including all of its subclauses, is conditionally normative.** > *Note*: The core C# language, as defined in the preceding clauses, differs notably from C and C++ in its omission of pointers as a data type. Instead, C# provides references and the ability to create objects that are managed by a garbage collector. This design, coupled with other features, makes C# a much safer language than C or C++. In the core C# language, it is simply not possible to have an uninitialized variable, a “dangling” pointer, or an expression that indexes an array beyond its bounds. Whole categories of bugs that routinely plague C and C++ programs are thus eliminated. -> +> > While practically every pointer type construct in C or C++ has a reference type counterpart in C#, nonetheless, there are situations where access to pointer types becomes a necessity. For example, interfacing with the underlying operating system, accessing a memory-mapped device, or implementing a time-critical algorithm might not be possible or practical without access to pointers. To address this need, C# provides the ability to write ***unsafe code***. -> +> > In unsafe code, it is possible to declare and operate on pointers, to perform conversions between pointers and integral types, to take the address of variables, and so forth. In a sense, writing unsafe code is much like writing C code within a C# program. -> +> > Unsafe code is in fact a “safe” feature from the perspective of both developers and users. Unsafe code shall be clearly marked with the modifier `unsafe`, so developers can’t possibly use unsafe features accidentally, and the execution engine works to ensure that unsafe code cannot be executed in an untrusted environment. *end note* ## 22.2 Unsafe contexts The unsafe features of C# are available only in unsafe contexts. An unsafe context is introduced by including an `unsafe` modifier in the declaration of a type or member, or by employing an *unsafe_statement*: -- A declaration of a class, struct, interface, or delegate may include an `unsafe` modifier, in which case, the entire textual extent of that type declaration (including the body of the class, struct, or interface) is considered an unsafe context. +- A declaration of a class, struct, interface, or delegate may include an `unsafe` modifier, in which case, the entire textual extent of that type declaration (including the body of the class, struct, or interface) is considered an unsafe context. > *Note*: If the *type_declaration* is partial, only that part is an unsafe context. *end note* - A declaration of a field, method, property, event, indexer, operator, instance constructor, finalizer, or static constructor may include an `unsafe` modifier, in which case, the entire textual extent of that member declaration is considered an unsafe context. - An *unsafe_statement* enables the use of an unsafe context within a *block*. The entire textual extent of the associated *block* is considered an unsafe context. @@ -78,7 +78,7 @@ Other than establishing an unsafe context, thus permitting the use of pointer ty > } > ``` > the unsafe modifier on the `F` method in `A` simply causes the textual extent of `F` to become an unsafe context in which the unsafe features of the language can be used. In the override of `F` in `B`, there is no need to re-specify the `unsafe` modifier—unless, of course, the `F` method in `B` itself needs access to unsafe features. -> +> > The situation is slightly different when a pointer type is part of the method’s signature > ```csharp > public unsafe class A @@ -117,7 +117,7 @@ Unlike references (values of reference types), pointers are not tracked by the g The intuitive rule for mixing of pointers and references is that referents of references (objects) are permitted to contain pointers, but referents of pointers are not permitted to contain references. > *Example*: Some examples of pointer types are given in the table below: -> +> > **Example** | **Description** > --------- | ----------- > `byte*` | Pointer to `byte` @@ -187,7 +187,7 @@ A *pointer_type* may be used as the type of a volatile field ([§14.5.4](classes > ``` > *end note* -A method can return a value of some type, and that type can be a pointer. +A method can return a value of some type, and that type can be a pointer. > *Example*: When given a pointer to a contiguous sequence of `int`s, that sequence’s element count, and some other `int` value, the following method returns the address of that value in that sequence, if a match occurs; otherwise it returns `null`: > ```csharp @@ -258,7 +258,7 @@ Finally, in an unsafe context, the set of standard implicit conversions ([§10.4 Conversions between two pointer types never change the actual pointer value. In other words, a conversion from one pointer type to another has no effect on the underlying address given by the pointer. -When one pointer type is converted to another, if the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined if the result is dereferenced. In general, the concept “correctly aligned” is transitive: if a pointer to type `A` is correctly aligned for a pointer to type `B`, which, in turn, is correctly aligned for a pointer to type `C`, then a pointer to type `A` is correctly aligned for a pointer to type `C`. +When one pointer type is converted to another, if the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined if the result is dereferenced. In general, the concept “correctly aligned” is transitive: if a pointer to type `A` is correctly aligned for a pointer to type `B`, which, in turn, is correctly aligned for a pointer to type `C`, then a pointer to type `A` is correctly aligned for a pointer to type `C`. > *Example*: Consider the following case in which a variable having one type is accessed via a pointer to a different type: > ```csharp @@ -360,7 +360,7 @@ The unary `*` operator denotes pointer indirection and is used to obtain the var The effect of applying the unary `*` operator to a `null`-valued pointer is implementation-defined. In particular, there is no guarantee that this operation throws a `System.NullReferenceException`. -If an invalid value has been assigned to the pointer, the behavior of the unary `*` operator is undefined. +If an invalid value has been assigned to the pointer, the behavior of the unary `*` operator is undefined. > *Note*: Among the invalid values for dereferencing a pointer by the unary `*` operator are an address inappropriately aligned for the type pointed to (see example in [§22.5](unsafe-code.md#225-pointer-conversions)), and the address of a variable after the end of its lifetime. @@ -472,7 +472,7 @@ A pointer element access of the form `P[E]` is evaluated exactly as `*(P + E)`. > ``` > *end example* -The pointer element access operator does not check for out-of-bounds errors and the behavior when accessing an out-of-bounds element is undefined. +The pointer element access operator does not check for out-of-bounds errors and the behavior when accessing an out-of-bounds element is undefined. > *Note*: This is the same as C and C++. *end note* @@ -486,7 +486,7 @@ addressof_expression ; ``` -Given an expression `E` which is of a type `T` and is classified as a fixed variable ([§22.4](unsafe-code.md#224-fixed-and-moveable-variables)), the construct `&E` computes the address of the variable given by `E`. The type of the result is `T*` and is classified as a value. A compile-time error occurs if `E` is not classified as a variable, if `E` is classified as a read-only local variable, or if `E` denotes a moveable variable. In the last case, a fixed statement ([§22.7](unsafe-code.md#227-the-fixed-statement)) can be used to temporarily “fix” the variable before obtaining its address. +Given an expression `E` which is of a type `T` and is classified as a fixed variable ([§22.4](unsafe-code.md#224-fixed-and-moveable-variables)), the construct `&E` computes the address of the variable given by `E`. The type of the result is `T*` and is classified as a value. A compile-time error occurs if `E` is not classified as a variable, if `E` is classified as a read-only local variable, or if `E` denotes a moveable variable. In the last case, a fixed statement ([§22.7](unsafe-code.md#227-the-fixed-statement)) can be used to temporarily “fix” the variable before obtaining its address. > *Note*: As stated in [§11.7.6](expressions.md#1176-member-access), outside an instance constructor or static constructor for a struct or class that defines a `readonly` field, that field is considered a value, not a variable. As such, its address cannot be taken. Similarly, the address of a constant cannot be taken. @@ -551,7 +551,7 @@ long operator –(T* x, T* y); Given an expression `P` of a pointer type `T*` and an expression `N` of type `int`, `uint`, `long`, or `ulong`, the expressions `P + N` and `N + P` compute the pointer value of type `T*` that results from adding `N * sizeof(T)` to the address given by `P`. Likewise, the expression `P – N` computes the pointer value of type `T*` that results from subtracting `N * sizeof(T)` from the address given by `P`. -Given two expressions, `P` and `Q`, of a pointer type `T*`, the expression `P – Q` computes the difference between the addresses given by `P` and `Q` and then divides that difference by `sizeof(T)`. The type of the result is always `long`. In effect, `P - Q` is computed as `((long)(P) - (long)(Q)) / sizeof(T)`. +Given two expressions, `P` and `Q`, of a pointer type `T*`, the expression `P – Q` computes the difference between the addresses given by `P` and `Q` and then divides that difference by `sizeof(T)`. The type of the result is always `long`. In effect, `P - Q` is computed as `((long)(P) - (long)(Q)) / sizeof(T)`. > *Example*: > ```csharp @@ -641,11 +641,11 @@ For each address computed by a *fixed_pointer_initializer* the `fixed` statement > *Example*: If the address computed by a *fixed_pointer_initializer* references a field of an object or an element of an array instance, the fixed statement guarantees that the containing object instance is not relocated or disposed of during the lifetime of the statement. *end example* -It is the programmer’s responsibility to ensure that pointers created by fixed statements do not survive beyond execution of those statements. +It is the programmer’s responsibility to ensure that pointers created by fixed statements do not survive beyond execution of those statements. > *Example*: When pointers created by `fixed` statements are passed to external APIs, it is the programmer’s responsibility to ensure that the APIs retain no memory of these pointers. *end example* -Fixed objects can cause fragmentation of the heap (because they can’t be moved). For that reason, objects should be fixed only when absolutely necessary and then only for the shortest amount of time possible. +Fixed objects can cause fragmentation of the heap (because they can’t be moved). For that reason, objects should be fixed only when absolutely necessary and then only for the shortest amount of time possible. > *Example*: The example > ```csharp @@ -674,7 +674,7 @@ Fixed objects can cause fragmentation of the heap (because they can’t be moved > } > ``` > demonstrates several uses of the `fixed` statement. The first statement fixes and obtains the address of a static field, the second statement fixes and obtains the address of an instance field, and the third statement fixes and obtains the address of an array element. In each case, it would have been an error to use the regular `&` operator since the variables are all classified as moveable variables. -> +> > The third and fourth `fixed` statements in the example above produce identical results. In general, for an array instance `a`, specifying `a[0]` in a `fixed` statement is the same as simply specifying `a`. *end example* In an unsafe context, array elements of single-dimensional arrays are stored in increasing index order, starting with index `0` and ending with index `Length – 1`. For multi-dimensional arrays, array elements are stored such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left. @@ -775,7 +775,7 @@ A `char*` value produced by fixing a string instance always points to a null-ter > ``` > *end example* -Modifying objects of managed type through fixed pointers can result in undefined behavior. +Modifying objects of managed type through fixed pointers can result in undefined behavior. > *Note*: For example, because strings are immutable, it is the programmer’s responsibility to ensure that the characters referenced by a pointer to a fixed string are not modified. *end note* @@ -789,7 +789,7 @@ Fixed-size buffers are used to declare “C-style” in-line arrays as members o ### 22.8.2 Fixed-size buffer declarations -A ***fixed-size buffer*** is a member that represents storage for a fixed-length buffer of variables of a given type. A fixed-size buffer declaration introduces one or more fixed-size buffers of a given element type. +A ***fixed-size buffer*** is a member that represents storage for a fixed-length buffer of variables of a given type. A fixed-size buffer declaration introduces one or more fixed-size buffers of a given element type. > *Note*: Like an array, a fixed-size buffer can be thought of as containing elements. As such, the term *element type* as defined for an array is also used with a fixed-size buffer. *end note* @@ -829,7 +829,7 @@ The buffer element type is followed by a list of fixed-size buffer declarators, The elements of a fixed-size buffer shall be laid out sequentially in memory. -A fixed-size buffer declaration that declares multiple fixed-size buffers is equivalent to multiple declarations of a single fixed-size buffer declaration with the same attributes, and element types. +A fixed-size buffer declaration that declares multiple fixed-size buffers is equivalent to multiple declarations of a single fixed-size buffer declaration with the same attributes, and element types. > *Example*: > ```csharp diff --git a/standard/variables.md b/standard/variables.md index aa516e9af..5f58ce0a3 100644 --- a/standard/variables.md +++ b/standard/variables.md @@ -80,7 +80,7 @@ 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 or anonymous function invocation. Thus, the value of a reference parameter is always the same as the underlying variable. -The following definite assignment rules apply to reference parameters. +The following definite assignment rules apply to reference parameters. > *Note*: The rules for output parameters are different, and are described in ([§9.2.7](variables.md#927-output-parameters)). *end note* @@ -95,7 +95,7 @@ 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. -The following definite assignment rules apply to output parameters. +The following definite assignment rules apply to output parameters. > *Note*: The rules for reference parameters are different, and are described in ([§9.2.6](variables.md#926-reference-parameters)). *end note* @@ -172,13 +172,13 @@ The definite assignment states of instance variables of a *struct_type* variable Definite assignment is a requirement in the following contexts: -- A variable shall be definitely assigned at each location where its value is obtained. +- A variable shall be definitely assigned at each location where its value is obtained. > *Note*: This ensures that undefined values never occur. *end note* The occurrence of a variable in an expression is considered to obtain the value of the variable, except when - the variable is the left operand of a simple assignment, - the variable is passed as an output parameter, or - 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. +- 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* - 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*