markdown fixes

This commit is contained in:
Maira Wenzel 2019-03-07 10:00:39 -08:00
parent 725763343a
commit 24289fe11c
5 changed files with 101 additions and 81 deletions

View file

@ -31,39 +31,40 @@ As such, the language should begin to support these operators to help advance th
[design]: #detailed-design
The full set of operators supported are defined in `III.1.5` of the Common Language Infrastructure specification (`ECMA-335`). The specification is available here: [https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf](https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf).
* A summary of the operators is provided below for convenience.
* The unverifiable operators defined by the CLI spec are not listed and are not currently part of this proposal (although it may be worth considering these as well).
* Providing a keyword (such as `nint` and `nuint`) nor providing a way to for literals to be declared for `System.IntPtr` and `System.UIntPtr` (such as 0n) is not part of this proposal (although it may be worth considering these as well).
#### Unary Plus Operator
### Unary Plus Operator
```C#
```csharp
System.IntPtr operator +(System.IntPtr)
```
```C#
```csharp
System.UIntPtr operator +(System.UIntPtr)
```
#### Unary Minus Operator
### Unary Minus Operator
```C#
```csharp
System.IntPtr operator -(System.IntPtr)
```
#### Bitwise Complement Operator
### Bitwise Complement Operator
```C#
```csharp
System.IntPtr operator ~(System.IntPtr)
```
```C#
```csharp
System.UIntPtr operator ~(System.UIntPtr)
```
#### Cast Operators
### Cast Operators
```C#
```csharp
explicit operator sbyte(System.IntPtr) // Truncate
explicit operator short(System.IntPtr) // Truncate
explicit operator int(System.IntPtr) // Truncate
@ -84,7 +85,7 @@ explicit operator System.IntPtr(System.IntPtr)
explicit operator System.IntPtr(System.UIntPtr)
```
```C#
```csharp
explicit operator sbyte(System.UIntPtr) // Truncate
explicit operator short(System.UIntPtr) // Truncate
explicit operator int(System.UIntPtr) // Truncate
@ -105,90 +106,91 @@ explicit operator System.UIntPtr(System.IntPtr)
explicit operator System.UIntPtr(System.UIntPtr)
```
#### Multiplication Operator
### Multiplication Operator
```C#
```csharp
System.IntPtr operator *(int, System.IntPtr)
System.IntPtr operator *(System.IntPtr, int)
System.IntPtr operator *(System.IntPtr, System.IntPtr)
```
```C#
```csharp
System.UIntPtr operator *(uint, System.UIntPtr)
System.UIntPtr operator *(System.UIntPtr, uint)
System.UIntPtr operator *(System.UIntPtr, System.UIntPtr)
```
#### Division Operator
### Division Operator
```C#
```csharp
System.IntPtr operator /(int, System.IntPtr)
System.IntPtr operator /(System.IntPtr, int)
System.IntPtr operator /(System.IntPtr, System.IntPtr)
```
```C#
```csharp
System.UIntPtr operator /(uint, System.UIntPtr)
System.UIntPtr operator /(System.UIntPtr, uint)
System.UIntPtr operator /(System.UIntPtr, System.UIntPtr)
```
#### Remainder Operator
### Remainder Operator
```C#
```csharp
System.IntPtr operator %(int, System.IntPtr)
System.IntPtr operator %(System.IntPtr, int)
System.IntPtr operator %(System.IntPtr, System.IntPtr)
```
```C#
```csharp
System.UIntPtr operator %(uint, System.UIntPtr)
System.UIntPtr operator %(System.UIntPtr, uint)
System.UIntPtr operator %(System.UIntPtr, System.UIntPtr)
```
#### Addition Operator
### Addition Operator
```C#
```csharp
System.IntPtr operator +(int, System.IntPtr)
System.IntPtr operator +(System.IntPtr, int)
System.IntPtr operator +(System.IntPtr, System.IntPtr)
```
```C#
```csharp
System.UIntPtr operator +(uint, System.UIntPtr)
System.UIntPtr operator +(System.UIntPtr, uint)
System.UIntPtr operator +(System.UIntPtr, System.UIntPtr)
```
#### Subtraction Operator
### Subtraction Operator
```C#
```csharp
System.IntPtr operator -(int, System.IntPtr)
System.IntPtr operator -(System.IntPtr, int)
System.IntPtr operator -(System.IntPtr, System.IntPtr)
```
```C#
```csharp
System.UIntPtr operator -(uint, System.UIntPtr)
System.UIntPtr operator -(System.UIntPtr, uint)
System.UIntPtr operator -(System.UIntPtr, System.UIntPtr)
```
#### Shift Operators
### Shift Operators
```C#
```csharp
System.IntPtr operator <<(System.IntPtr, int)
System.IntPtr operator >>(System.IntPtr, int)
```
```C#
```csharp
System.UIntPtr operator <<(System.UIntPtr, int)
System.UIntPtr operator >>(System.UIntPtr, int)
```
#### Integer Comparison Operators
```C#
### Integer Comparison Operators
```csharp
bool operator ==(int, System.IntPtr)
bool operator ==(System.IntPtr, int)
bool operator ==(System.IntPtr, System.IntPtr)
@ -214,7 +216,7 @@ bool operator >=(System.IntPtr, int)
bool operator >=(System.IntPtr, System.IntPtr)
```
```C#
```csharp
bool operator ==(uint, System.UIntPtr)
bool operator ==(System.UIntPtr, uint)
bool operator ==(System.UIntPtr, System.UIntPtr)
@ -240,9 +242,9 @@ bool operator >=(System.UIntPtr, uint)
bool operator >=(System.UIntPtr, System.UIntPtr)
```
#### Integer Logical Operators
### Integer Logical Operators
```C#
```csharp
System.IntPtr operator &(int, System.IntPtr)
System.IntPtr operator &(System.IntPtr, int)
System.IntPtr operator &(System.IntPtr, System.IntPtr)
@ -256,7 +258,7 @@ System.IntPtr operator ^(System.IntPtr, int)
System.IntPtr operator ^(System.IntPtr, System.IntPtr)
```
```C#
```csharp
System.UIntPtr operator &(uint, System.UIntPtr)
System.UIntPtr operator &(System.UIntPtr, uint)
System.UIntPtr operator &(System.UIntPtr, System.UIntPtr)
@ -287,6 +289,4 @@ What parts of the design are still TBD?
## Design meetings
Link to design notes that affect this proposal, and describe in one sentence for each what changes they led to.
Link to design notes that affect this proposal, and describe in one sentence for each what changes they led to.

View file

@ -14,18 +14,22 @@ Allow attributes to be applied to lambdas (and anonymous methods) and to lambda
[motivation]: #motivation
Two primary motivations:
1. To provide metadata visible to analyzers at compile-time.
2. To provide metadata visible to reflection and tooling at run-time.
As an example of (1):
For performance-sensitive code, it is helpful to be able to have an analyzer that flags when closures and delegates are being allocated for lambdas that close over state. Often a developer of such code will go out of his or her way to avoid capturing any state, so that the compiler can generate a static method and a cacheable delegate for the method, or the developer will ensure that the only state being closed over is `this`, allowing the compiler at least to avoid allocating a closure object. But, without language support for limiting what may be captured, it is all too easy to accidentally close over state. It would be valuable if a developer could annotate lambdas with attributes to indicate what state they're allowed to close over, e.g.
```C#
For performance-sensitive code, it is helpful to be able to have an analyzer that flags when closures and delegates are being allocated for lambdas that close over state. Often a developer of such code will go out of his or her way to avoid capturing any state, so that the compiler can generate a static method and a cacheable delegate for the method, or the developer will ensure that the only state being closed over is `this`, allowing the compiler at least to avoid allocating a closure object. But, without language support for limiting what may be captured, it is all too easy to accidentally close over state. It would be valuable if a developer could annotate lambdas with attributes to indicate what state they're allowed to close over, for example:
```csharp
[CaptureNone] // can't close over any instance state
[CaptureThis] // can only capture `this` and no other instance state
[CaptureAny] // can close over any instance state
```
Then an analyzer can be written to flag when state is captured incorrectly, e.g.
```C#
Then an analyzer can be written to flag when state is captured incorrectly, for example:
```csharp
var results = collection.Select([CaptureNone](i) => Process(item)); // Analyzer error: [CaptureNone] lambdas captures `this`
...
private U Process(T item) { ... }
@ -34,53 +38,54 @@ private U Process(T item) { ... }
## Detailed design
[design]: #detailed-design
- Using the same attribute syntax as on normal methods, attributes may be applied at the beginning of a lambda or anonymous method, e.g.
- Using the same attribute syntax as on normal methods, attributes may be applied at the beginning of a lambda or anonymous method, for example:
```C#
```csharp
[SomeAttribute(...)] () => { ... }
[SomeAttribute(...)] delegate (int i) { ... }
```
- To avoid ambiguity as to whether an attribute applies to the lambda method or to one of the arguments, attributes may only be used when parens are used around any arguments, e.g.
- To avoid ambiguity as to whether an attribute applies to the lambda method or to one of the arguments, attributes may only be used when parens are used around any arguments, for example:
```C#
```csharp
[SomeAttribute] i => { ... } // ERROR
[SomeAttribute] (i) => { ... } // Ok
[SomeAttribute] (int i) => { ... } // Ok
```
- With anonymous methods, parens are not needed in order to apply an attribute to the method before the `delegate` keyword, e.g.
- With anonymous methods, parens are not needed in order to apply an attribute to the method before the `delegate` keyword, for example:
```C#
```csharp
[SomeAttribute] delegate { ... } // Ok
[SomeAttribute] delegate (int i) => { ... } // Ok
```
- Multiple attributes may be applied, either via standard comma-delimited syntax or via full-attribute syntax, e.g.
- Multiple attributes may be applied, either via standard comma-delimited syntax or via full-attribute syntax, for example:
```C#
```csharp
[FirstAttribute, SecondAttribute] (i) => { ... } // Ok
[FirstAttribute] [SecondAttribute] (i) => { .... } // Ok
```
- Attributes may be applied to the parameters to an anonymous method or lambda, but only when parens are used around any arguments, e.g.
- Attributes may be applied to the parameters to an anonymous method or lambda, but only when parens are used around any arguments, for example:
```C#
```csharp
[SomeAttribute] i => { ... } // ERROR
([SomeAttribute] i) => { .... } // Ok
([SomeAttribute] int i) => { ... } // Ok
([SomeAttribute] i, [SomeOtherAttribute] j) => { ... } // Ok
```
- Multiple attributes may be applied to the parameters of an anonymous method or lambda, using either the comma-delimited or full-attribute syntax, e.g.
- Multiple attributes may be applied to the parameters of an anonymous method or lambda, using either the comma-delimited or full-attribute syntax, for example:
```C#
```csharp
([FirstAttribute, SecondAttribute] i) => { ... } // Ok
([FirstAttribute] [SecondAttribute] i) => { ... } // Ok
```
- `return`-targeted attributes may also be used on lambdas, e.g.
```C#
- `return`-targeted attributes may also be used on lambdas, for example:
```csharp
([return: SomeAttribute] (i) => { ... }) // Ok
```
@ -103,4 +108,4 @@ n/a
## Design meetings
n/a
n/a

View file

@ -20,7 +20,7 @@ This is a common coding pattern, and this feature would have nice synergy with t
We add a new form of the *await_expression*:
``` antlr
```antlr
await_expression
: 'await' '?' unary_expression
;
@ -32,7 +32,7 @@ The type of the result is computed using the [rules for the null-conditional ope
> **NOTE:**
> If `e` is of type `Task`, then `await? e;` would do nothing if `e` is `null`, and await `e` if it is not `null`.
>
>
> If `e` is of type `Task<K>` where `K` is a value type, then `await? e` would yield a value of type `K?`.
## Drawbacks

View file

@ -1,6 +1,6 @@
# Readonly Instance Members
Championed Issue: https://github.com/dotnet/csharplang/issues/1710
Championed Issue: <https://github.com/dotnet/csharplang/issues/1710>
## Summary
[summary]: #summary
@ -25,7 +25,7 @@ Some other scenarios where hidden copies can occur include `static readonly fiel
Allow a user to specify that an instance member is, itself, `readonly` and does not modify the state of the instance (with all the appropriate verification done by the compiler, of course). For example:
```C#
```csharp
public struct Vector2
{
public float x;
@ -87,7 +87,8 @@ public static class MyClass
```
Readonly can be applied to property accessors to indicate that `this` will not be mutated in the accessor.
```cs
```csharp
public int Prop1
{
readonly get
@ -102,7 +103,8 @@ public int Prop1
```
When `readonly` is applied to the property syntax, it means that all accessors are `readonly`.
```cs
```csharp
public readonly int Prop2
{
get
@ -117,7 +119,8 @@ public readonly int Prop2
```
Readonly can only be applied to accessors which do not mutate the containing type.
```cs
```csharp
public int Prop3
{
readonly get
@ -132,7 +135,8 @@ public int Prop3
```
Readonly can be applied to some auto-implemented properties, but it won't have a meaningful effect. The compiler will treat all auto-implemented getters as readonly whether or not the `readonly` keyword is present.
```cs
```csharp
// Allowed
public readonly int Prop4 { get; }
public int Prop5 { readonly get; }
@ -144,7 +148,8 @@ public int Prop8 { get; readonly set; }
```
Readonly can be applied to manually-implemented events, but not field-like events. Readonly cannot be applied to individual event accessors (add/remove).
```cs
```csharp
// Allowed
public readonly event Action<EventArgs> Event1
{
@ -167,6 +172,7 @@ public static readonly event Event4
```
Some other syntax examples:
* Expression bodied members: `public readonly float ExpressionBodiedMember => (x * x) + (y * y);`
* Generic constraints: `public static readonly void GenericMethod<T>(T value) where T : struct { }`
@ -175,12 +181,13 @@ The compiler would emit the instance member, as usual, and would additionally em
This would allow the user to safely call said instance method without the compiler needing to make a copy.
The restrictions would include:
* The `readonly` modifier cannot be applied to static methods, constructors or destructors.
* The `readonly` modifier cannot be applied to delegates.
* The `readonly` modifier cannot be applied to members of class or interface.
## Drawbacks
[drawbacks]: #drawbacks
[drawbacks]: #drawbacks
Same drawbacks as exist with `readonly struct` methods today. Certain code may still cause hidden copies.

View file

@ -16,7 +16,7 @@ Allow locals and parameters to be annotated as readonly in order to prevent shal
Today, the `readonly` keyword can be applied to fields; this has the effect of ensuring that a field can only
be written to during construction (static construction in the case of a static field, or instance construction in the case of an instance field),
which helps developers avoid mistakes by accidentally overwriting state which should not be modified. But fields aren't the only places developers
want to ensure that values aren't mutated. In particular, it's common to create a local variable to store temporary state, and accidentally updating
want to ensure that values aren't mutated. In particular, it's common to create a local variable to store temporary state, and accidentally updating
that temporary state can result in erroneous calculations and other such bugs, especially when such "locals" are captured in lambdas, at which point
they are lifted to fields, but there's no way today to mark such lifted fields as 'readonly`.
@ -25,30 +25,36 @@ they are lifted to fields, but there's no way today to mark such lifted fields a
Locals will be annotatable as `readonly` as well, with the compiler ensuring that they're only set at the time of declaration (certain locals in C# are
already implicitly readonly, such as the iteration variable in a 'foreach' loop or the used variable in a 'using' block, but currently a developer has
no ability to mark other locals as `readonly`). Such `readonly` locals must have an initializer:
``` C#
no ability to mark other locals as `readonly`). Such `readonly` locals must have an initializer:
```csharp
readonly long maxBytesToDelete = (stream.LimitBytes - stream.MaxBytes) / 10;
...
maxBytesToDelete = 0; // Error: can't assign to readonly locals outside of declaration
```
And as shorthand for `readonly var`, the existing contextual keyword `let` may be used, e.g.
```C#
```csharp
let maxBytesToDelete = (stream.LimitBytes - stream.MaxBytes) / 10;
...
maxBytesToDelete = 0; // Error: can't assign to readonly locals outside of declaration
```
There are no special constraints for what the initializer can be, and can be anything currently valid as an initializer for locals, e.g.
```C#
```csharp
readonly T data = arg1 ?? arg2;
```
`readonly` on locals is particularly valuable when working with lambdas and closures. When an anonymous method or lambda accesses local state from the enclosing scope,
`readonly` on locals is particularly valuable when working with lambdas and closures. When an anonymous method or lambda accesses local state from the enclosing scope,
that state is captured into a closure by the compiler, which is represented by a "display class." Each "local" that's captured is a field in this class, yet
because the compiler is generating this field on your behalf, you have no opportunity to annotate it as `readonly` in order to prevent the lambda from erroneously
writing to the "local" (in quotes because it's really not a local, at least not in the resulting MSIL). With `readonly` locals, the compiler can prevent the lambda
writing to the "local" (in quotes because it's really not a local, at least not in the resulting MSIL). With `readonly` locals, the compiler can prevent the lambda
from writing to local, which is particularly valuable in scenarios involving multithreading where an erroneous write could result in a dangerous but rare and
hard-to-find concurrency bug.
``` C#
```csharp
readonly long index = ...;
Parallel.ForEach(data, item => {
T element = item[index];
@ -56,19 +62,21 @@ Parallel.ForEach(data, item => {
});
```
As a special form of local, parameters will also be annotatable as `readonly`. This would have no effect on what the caller of the method is able to pass to the
As a special form of local, parameters will also be annotatable as `readonly`. This would have no effect on what the caller of the method is able to pass to the
parameter (just as there's no constraint on what values may be stored into a `readonly` field), but as with any `readonly` local, the compiler would prohibit code
from writing to the parameter after declaration, which means the body of the method is prohibited from writing to the parameter.
``` C#
```csharp
public void Update(readonly int index = 0) // Default values are ok though not required
{
...
index = 0; // Error: can't assign to readonly parameters
...
...
}
```
`readonly` parameters do not affect the signature/metadata emitted by the compiler for that method, and simply affect how the compiler handles the compilation of
the method's body. Thus, for example, a base virtual method could have a `readonly` parameter, and that parameter could be writable in an override.
the method's body. Thus, for example, a base virtual method could have a `readonly` parameter, and that parameter could be writable in an override.
As with fields, `readonly` for locals and parameters is shallow, affecting the storage location but not transitively affecting the object graph. However, also
as with fields, calling a method on a `readonly` local/parameter struct will actually make a copy of the struct and call the method on the copy, in order to avoid
@ -85,8 +93,8 @@ internal mutation of `this`.
[unresolved]: #unresolved-questions
- `readonly ref` / `ref readonly` / `readonly ref readonly`: I've left the question of how to handle `ref readonly` as separate from this proposal.
- This proposal does not tackle readonly structs / immutable types. That is left for a separate proposal.
- This proposal does not tackle readonly structs / immutable types. That is left for a separate proposal.
## Design meetings
- Briefly discussed on Jan 21, 2015 (https://github.com/dotnet/roslyn/issues/98)
- Briefly discussed on Jan 21, 2015 (<https://github.com/dotnet/roslyn/issues/98>)