From b3aaa91995b7ea4251b16c53ec43cb1e246e1e5c Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Fri, 1 Jun 2018 16:25:39 -0700 Subject: [PATCH 1/2] Clarify Span rules While discussing `Span` safety rules with the F# team I realized we hadn't fully documented our dependency on the shape of the `Span` API. Added that plus some of the future considerations we discussed for `Span`. https://github.com/Microsoft/visualfsharp/pull/4888 --- proposals/csharp-7.2/span-safety.md | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/proposals/csharp-7.2/span-safety.md b/proposals/csharp-7.2/span-safety.md index 96de8d5336..65bc29816f 100644 --- a/proposals/csharp-7.2/span-safety.md +++ b/proposals/csharp-7.2/span-safety.md @@ -236,6 +236,20 @@ A `new` expression that invokes a constructor obeys the same rules as a method i In addition *safe-to-escape* is no wider than the smallest of the *safe-to-escape* of all arguments/operands of the object initializer expressions, recursively, if initializer is present. +## Span constructor +The language relies on `Span` not having a constructor of the following form: + +``` csharp +void Example(ref int x) +{ + // Create a span of length one + var span = new Span(ref x); +} +``` + +Such a constructor makes `Span` which are used as fields indistinguishable from a `ref` field. The safety rules described in this document +depend on `ref` fields not being a valid construct in C#, or .NET. + ## `default` expressions A `default` expression is *safe-to-escape* from the entire enclosing method. @@ -280,3 +294,37 @@ We wish to ensure that no `ref` local variable, and no variable of `ref struct` > ``` c# > Foo(new Span(...), await e2); > ``` + +# Future Considerations + +## Length one Span over ref values +Though legal today there are cases where creating a length one `Span` instance over a value would be beneficial: + +``` csharp +void RefExample() +{ + int x = ...; + + // Today creating a length one Span requires a stackalloc and a new + // local + Span span1 = stackalloc [] { x }; + Use(span1); + x = span1[0]; + + // Simpler to just allow length one span + var span2 = new Span(ref x); + Use(span2); +} +``` + +This feature gets more compelling if we lift the restrictions on (fixed sized buffers)[https://github.com/dotnet/csharplang/blob/master/proposals/fixed-sized-buffers.md] as it would +allow for `Span` instances of even greater length. + +If there is ever a need to go down this path then the language could accommodate this by ensuring such `Span` instances +were downward facing only. That is they were only ever *safe-to-escape* to the scope in which they were created. This ensure +the language never had to consider a `ref` value escaping a method via a `ref struct` return or field of `ref struct`. This +would likely also require further changes to recognize such constructors as capturing a `ref` parameter in this way though. + + + + From d0da08208940cdb09348ace7595eaa82a9259ac5 Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Mon, 4 Jun 2018 10:25:36 -0700 Subject: [PATCH 2/2] Respond to PR feedback --- proposals/csharp-7.2/span-safety.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/csharp-7.2/span-safety.md b/proposals/csharp-7.2/span-safety.md index 65bc29816f..88649658d0 100644 --- a/proposals/csharp-7.2/span-safety.md +++ b/proposals/csharp-7.2/span-safety.md @@ -55,7 +55,7 @@ A typical metadata representation: } ``` -NOTE: it is not the goal to make it so that any use of ref-like types on old compilers fails 100%. That is hard to achieve and is not strictly necessary. For example there would always be away to get around the `Obsolete` using dynamic code or, for example, creating an array of ref-like types through reflection. +NOTE: it is not the goal to make it so that any use of ref-like types on old compilers fails 100%. That is hard to achieve and is not strictly necessary. For example there would always be a way to get around the `Obsolete` using dynamic code or, for example, creating an array of ref-like types through reflection. In particular, if user wants to actually put an `Obsolete` or `Deprecated` attribute on a ref-like type, we will have no choice other than not emitting the predefined one since `Obsolete` attribute cannot be applied more than once.. @@ -298,7 +298,7 @@ We wish to ensure that no `ref` local variable, and no variable of `ref struct` # Future Considerations ## Length one Span over ref values -Though legal today there are cases where creating a length one `Span` instance over a value would be beneficial: +Though not legal today there are cases where creating a length one `Span` instance over a value would be beneficial: ``` csharp void RefExample()