markdown fixes
This commit is contained in:
parent
725763343a
commit
24289fe11c
|
@ -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.
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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>)
|
Loading…
Reference in a new issue