markdown lint for C# 7.1 proposals

These had two sets of changes:

1. use `csharp` as the language identifier for code fences.
1. use relative links to other articles in the dotnet/csharplang repo that are being published on docs.microsoft.com so those links resolve to the article published there from that site.
This commit is contained in:
Bill Wagner 2019-03-07 11:50:08 -05:00
parent 0298b8676f
commit 74f60810a3
3 changed files with 21 additions and 10 deletions

View file

@ -17,7 +17,8 @@ It is very common when learning C#, when writing console-based utilities, and wh
to call and `await` `async` methods from Main. Today we add a level of complexity here by forcing such `await`'ing to be to call and `await` `async` methods from Main. Today we add a level of complexity here by forcing such `await`'ing to be
done in a separate async method, which causes developers to need to write boilerplate like the following just to get done in a separate async method, which causes developers to need to write boilerplate like the following just to get
started: started:
```C#
```csharp
public static void Main() public static void Main()
{ {
MainAsync().GetAwaiter().GetResult(); MainAsync().GetAwaiter().GetResult();
@ -28,6 +29,7 @@ private static async Task MainAsync()
... // Main body here ... // Main body here
} }
``` ```
We can remove the need for this boilerplate and make it easier to get started simply by allowing Main itself to be We can remove the need for this boilerplate and make it easier to get started simply by allowing Main itself to be
`async` such that `await`s can be used in it. `async` such that `await`s can be used in it.
@ -35,7 +37,8 @@ We can remove the need for this boilerplate and make it easier to get started si
[design]: #detailed-design [design]: #detailed-design
The following signatures are currently allowed entrypoints: The following signatures are currently allowed entrypoints:
```C#
```csharp
static void Main() static void Main()
static void Main(string[]) static void Main(string[])
static int Main() static int Main()
@ -43,12 +46,14 @@ static int Main(string[])
``` ```
We extend the list of allowed entrypoints to include: We extend the list of allowed entrypoints to include:
```
```csharp
static Task Main() static Task Main()
static Task<int> Main() static Task<int> Main()
static Task Main(string[]) static Task Main(string[])
static Task<int> Main(string[]) static Task<int> Main(string[])
``` ```
To avoid compatibility risks, these new signatures will only be considered as valid entrypoints if no overloads of the previous set are present. To avoid compatibility risks, these new signatures will only be considered as valid entrypoints if no overloads of the previous set are present.
The language / compiler will not require that the entrypoint be marked as `async`, though we expect the vast majority of uses will be marked as such. The language / compiler will not require that the entrypoint be marked as `async`, though we expect the vast majority of uses will be marked as such.
@ -59,7 +64,8 @@ When one of these is identified as the entrypoint, the compiler will synthesize
- ```static Task<int> Main(string[])``` will result in the compiler emitting the equivalent of ```private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();``` - ```static Task<int> Main(string[])``` will result in the compiler emitting the equivalent of ```private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();```
Example usage: Example usage:
```C#
```csharp
using System; using System;
using System.Net.Http; using System.Net.Http;
@ -81,14 +87,17 @@ The main drawback is simply the additional complexity of supporting additional e
Other variants considered: Other variants considered:
Allowing `async void`. We need to keep the semantics the same for code calling it directly, which would then make it difficult for a generated entrypoint to call it (no Task returned). We could solve this by generating two other methods, e.g. Allowing `async void`. We need to keep the semantics the same for code calling it directly, which would then make it difficult for a generated entrypoint to call it (no Task returned). We could solve this by generating two other methods, e.g.
```C#
```csharp
public static async void Main() public static async void Main()
{ {
... // await code ... // await code
} }
``` ```
becomes becomes
```C#
```csharp
public static async void Main() => await $MainTask(); public static async void Main() => await $MainTask();
private static void $EntrypointMain() => Main().GetAwaiter().GetResult(); private static void $EntrypointMain() => Main().GetAwaiter().GetResult();
@ -98,6 +107,7 @@ private static async Task $MainTask()
... // await code ... // await code
} }
``` ```
There are also concerns around encouraging usage of `async void`. There are also concerns around encouraging usage of `async void`.
Using "MainAsync" instead of "Main" as the name. While the async suffix is recommended for Task-returning methods, that's primarily about library functionality, which Main is not, and supporting additional entrypoint names beyond "Main" is not worth it. Using "MainAsync" instead of "Main" as the name. While the async suffix is recommended for Task-returning methods, that's primarily about library functionality, which Main is not, and supporting additional entrypoint names beyond "Main" is not worth it.

View file

@ -8,7 +8,7 @@
## Summary ## Summary
[summary]: #summary [summary]: #summary
The specification for the [existing C# as operator](https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#the-as-operator) permits there to be no conversion between the type of the operand and the specified type when either is an open type. However, in C# 7 the `Type identifier` pattern requires there be a conversion between the type of the input and the given type. The specification for the [existing C# as operator](../../spec/expressions.md#the-as-operator) permits there to be no conversion between the type of the operand and the specified type when either is an open type. However, in C# 7 the `Type identifier` pattern requires there be a conversion between the type of the input and the given type.
We propose to relax this and change `expression is Type identifier`, in addition to being permitted in the conditions when it is permitted in C# 7, to also be permitted when `expression as Type` would be allowed. Specifically, the new cases are cases where the type of the expression or the specified type is an open type. We propose to relax this and change `expression is Type identifier`, in addition to being permitted in the conditions when it is permitted in C# 7, to also be permitted when `expression as Type` would be allowed. Specifically, the new cases are cases where the type of the expression or the specified type is an open type.

View file

@ -9,7 +9,7 @@ This parallels the behavior of anonymous types, which allow inferring member na
This is particularly handy when using tuples in LINQ: This is particularly handy when using tuples in LINQ:
``` ```csharp
// "c" and "result" have element names "f1" and "f2" // "c" and "result" have element names "f1" and "f2"
var result = list.Select(c => (c.f1, c.f2)).Where(t => t.f2 == 1); var result = list.Select(c => (c.f1, c.f2)).Where(t => t.f2 == 1);
``` ```
@ -30,7 +30,8 @@ There are two parts to the change:
Note that the rule for handling duplicates is different than that for anonymous types. For instance, `new { x.f1, x.f1 }` produces an error, but `(x.f1, x.f1)` would still be allowed (just without any inferred names). This avoids breaking existing tuple code. Note that the rule for handling duplicates is different than that for anonymous types. For instance, `new { x.f1, x.f1 }` produces an error, but `(x.f1, x.f1)` would still be allowed (just without any inferred names). This avoids breaking existing tuple code.
For consistency, the same would apply to tuples produced by deconstruction-assignments (in C#): For consistency, the same would apply to tuples produced by deconstruction-assignments (in C#):
```C#
```csharp
// tuple has element names "f1" and "f2" // tuple has element names "f1" and "f2"
var tuple = ((x.f1, x?.f2) = (1, 2)); var tuple = ((x.f1, x?.f2) = (1, 2));
``` ```
@ -44,7 +45,7 @@ When using the C# 7.1 compiler (or later) with language version "7.0", the eleme
The main drawback is that this introduces a compatibility break from C# 7.0: The main drawback is that this introduces a compatibility break from C# 7.0:
```C# ```csharp
Action y = () => M(); Action y = () => M();
var t = (x: x, y); var t = (x: x, y);
t.y(); // this might have previously picked up an extension method called “y”, but would now call the lambda. t.y(); // this might have previously picked up an extension method called “y”, but would now call the lambda.