diff --git a/proposals/csharp-7.2/span-safety.md b/proposals/csharp-7.2/span-safety.md index 96de8d5336..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.. @@ -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 not 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. + + + +