Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create inline-arrays.md #7064

Merged
merged 39 commits into from
Apr 14, 2023
Merged
Changes from 2 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
47f5c9a
Create safe-fixed-sized-buffers.md
AlekseyTs Mar 16, 2023
1e15e61
Update safe-fixed-sized-buffers.md
AlekseyTs Mar 16, 2023
6ca5ef5
Apply suggestions from code review
AlekseyTs Mar 16, 2023
ecaa0c6
Update safe-fixed-sized-buffers.md
AlekseyTs Mar 16, 2023
178356d
Update safe-fixed-sized-buffers.md
AlekseyTs Mar 16, 2023
ffffc7b
Update safe-fixed-sized-buffers.md
AlekseyTs Mar 16, 2023
6604a84
Delete fixed-sized-buffers.md
AlekseyTs Mar 16, 2023
26e058c
Create fixed-sized-buffers.md
AlekseyTs Mar 16, 2023
38d3217
Rename safe-fixed-sized-buffers.md to safe-fixed-size-buffers.md
AlekseyTs Mar 17, 2023
f92dadb
Update safe-fixed-size-buffers.md
AlekseyTs Mar 17, 2023
7d40dc1
Update safe-fixed-size-buffers.md
AlekseyTs Mar 18, 2023
79099cd
PR feedback
AlekseyTs Mar 20, 2023
a3ffcad
Add an alternative design
AlekseyTs Mar 21, 2023
8b8a86a
Update safe-fixed-size-buffers.md
AlekseyTs Mar 21, 2023
2924ee1
Update safe-fixed-size-buffers.md
AlekseyTs Mar 22, 2023
1426407
Update safe-fixed-size-buffers.md
AlekseyTs Mar 22, 2023
77e6a30
Update safe-fixed-size-buffers.md
AlekseyTs Mar 23, 2023
f793250
Apply suggestions from code review
AlekseyTs Mar 28, 2023
211cad3
Swap design options in safe-fixed-size-buffers.md
AlekseyTs Mar 31, 2023
b57d7e3
PR feedback for safe-fixed-size-buffers.md
AlekseyTs Mar 31, 2023
368c395
Clarify "Element access" section in safe-fixed-size-buffers.md
AlekseyTs Mar 31, 2023
6df9506
Update safe-fixed-size-buffers.md
AlekseyTs Mar 31, 2023
1b85bcd
Clarify "Conversions" section in safe-fixed-size-buffers.md
AlekseyTs Mar 31, 2023
5d23036
Update safe-fixed-size-buffers.md
AlekseyTs Mar 31, 2023
9b8924a
Clarifying "Fixed-size buffers in expressions" section in safe-fixed-…
AlekseyTs Mar 31, 2023
c4d683d
Update safe-fixed-size-buffers.md
AlekseyTs Apr 1, 2023
b7acdb8
Update safe-fixed-size-buffers.md
AlekseyTs Apr 1, 2023
a9abf26
Update safe-fixed-size-buffers.md
AlekseyTs Apr 3, 2023
884c33a
Add nn alternative to relying on AsSpan/AsReadOnlySpan helpers to saf…
AlekseyTs Apr 4, 2023
39e641b
Don't use pointers
AlekseyTs Apr 4, 2023
bda99a6
Update primary-constructors.md based on recent LDM decisions (#7099)
AlekseyTs Apr 7, 2023
30cc4ad
Revert "Update primary-constructors.md based on recent LDM decisions …
AlekseyTs Apr 7, 2023
e264575
Move "Detailed Design (Option 2)" to the "Alternatives" section in sa…
AlekseyTs Apr 11, 2023
938151a
Update safe-fixed-size-buffers.md
AlekseyTs Apr 11, 2023
0858400
Update safe-fixed-size-buffers.md
AlekseyTs Apr 11, 2023
fc9b629
Rename safe-fixed-size-buffers.md to inline-array.md
AlekseyTs Apr 14, 2023
b01c730
Rename feature to "Inline Array" from "Safe Fixed Size Buffers" in i…
AlekseyTs Apr 14, 2023
8606658
Rename inline-array.md to inline-arrays.md
AlekseyTs Apr 14, 2023
874228a
Update inline-arrays.md
AlekseyTs Apr 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions proposals/safe-fixed-sized-buffers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
Safe Fixed Size Buffers
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved
=====

## Summary

Provide a general-purpose and safe mechanism for declaring fixed sized buffers within C# classes, structs and interfaces.
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved

## Motivation

This proposal plans to address the many limitations of https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#228-fixed-size-buffers.
Specifically it aims to allow the declaration of safe `fixed` buffers for managed and unmanaged types in a `struct`, `class`, or `interface`.
And provide language safety verification for them.
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved

## Detailed Design

Grammar for `variable_declarator` in https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/classes.md#145-fields
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved
will be extended to allow specifying the size of the buffer:

``` antlr
field_declaration
: attributes? field_modifier* type variable_declarators ';'
;

field_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
| 'static'
| 'readonly'
| 'volatile'
| unsafe_modifier // unsafe code support
;

variable_declarators
: variable_declarator (',' variable_declarator)*
;

variable_declarator
: identifier ('=' variable_initializer)?
| fixed_size_buffer_declarator
;

fixed_size_buffer_declarator
: identifier '[' constant_expression ']'
;
```

A `fixed_size_buffer_declarator` introduces a fixed-size buffers of a given element type.
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved

The buffer element type is the `type` specified in `field_declaration`. A fixed-size buffer declarator introduces a new member and consists of an identifier that names the member, followed by a constant expression enclosed in `[` and `]` tokens. The constant expression denotes the number of elements in the member introduced by that fixed-size buffer declarator. The type of the constant expression shall be implicitly convertible to type `int`, and the value shall be a non-zero positive integer.
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved

The elements of a fixed-size buffer shall be laid out sequentially in memory as though they are elements of an array.

A `volatile` modifier cannot be used with `fixed_size_buffer_declarator`. A System.ThreadStaticAttribute cannot be applied to a field declaration like that.
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved

Depending on the situation (details are specified below), an access to a fixes-size buffer member is classified as a value (never a variable) of either
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved
`System.ReadOnlySpan<S>` or `System.Span<S>`, where S is the element type of the fixed-size buffer. Both types provide indexers returning refernce to a
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved
specific element with appropriate "readonly-ness". Which prevents direct assignment to the elements when language rules don't permit that.
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved

The resulting span instance will have a length equal to the size declared on the fixed-size buffer.
Indexing into the span with a constant expression outside of the declared fixed-size buffer bounds is a compile time error.

The `safe-to-escape` scope of the value will be equal to the `safe-to-escape` scope of the container, just as it would if the backing data was accessed as a field.
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved

### Fixed-size buffers in expressions

Member lookup of a fixed-size buffer member proceeds exactly like member lookup of a field.

A fixed-size buffer can be referenced in an expression using a *simple_name* or a *member_access* .

When an instance fixed-size buffer member is referenced as a simple name, the effect is the same as a member access of the form `this.I`, where `I` is the fixed-size buffer member. When a static fixed-size buffer member is referenced as a simple name, the effect is the same as a member access of the form `E.I`, where `I` is the fixed-size buffer member and `E` is the declaring type.

#### Non-readonly fixed-size buffers

In a member access of the form `E.I`, if `E` is of a struct type and a member lookup of `I` in that struct type identifies an instance fixed-size member,
then `E.I` is evaluated and classified as follows:

- If `E` is classified as a value, the result of the expression is classified as a value of type `System.ReadOnlySpan<S>`, where S is the element type of `I`.
AlekseyTs marked this conversation as resolved.
Show resolved Hide resolved
The value can be used to access members’ elements.
- Otherwise, `E` is classified as a variable and the result of the expression is classified as a value of type `System.Span<S>`, where S is the element type of `I`.
The value can be used to access members’ elements.

In a member access of the form `E.I`, if `E` is of a class type and a member lookup of `I` in that class type identifies an instance fixed-size member,
then `E.I` is evaluated and classified as a value of type `System.Span<S>`, where S is the element type of `I`.

In a member access of the form `E.I`, if member lookup of `I` identifies a static fixed-size member,
then `E.I` is evaluated and classified as a value of type `System.Span<S>`, where S is the element type of `I`.

#### Readonly fixed-size buffers

When a *field_declaration* includes a `readonly` modifier, the member introduced by the fixed_size_buffer_declarator is a ***readony fixed-size buffer***.
Direct assignments to elements of a readonly fixed-size buffer can only occur in an instance constructor, init member or static constructor in the same type.
Specifically, direct assignments to an element of readonly fixed-size buffer are permitted only in the following contexts:

- For an instance member, in the instance constructors or init member of the type that contains the member declaration; for a static member,
in the static constructor of the type that contains the member declaration. These are also the only contexts in which it is valid to pass
an element of readonly fixed-size buffer as an `out` or `ref` parameter.

Attempting to assign to an element of a readonly fixed-size buffer or pass it as an `out` or `ref` parameter in any other context is a compile-time error.
This is achieved by the following.

A member access for a readonly fixed-size buffer is evaluated and classified as follows:

- If access occurs in a context where direct assignments to an element of readonly fixed-size buffer are permitted, the result of the expression is classified as a value of type `System.Span<S>`, where S is the element type of the fixed-size buffer.
The value can be used to access members’ elements.
- Otherwise, the expression is classified as a value of type `System.ReadOnlySpan<S>`, where S is the element type of the fixed-size buffer.
The value can be used to access members’ elements.

### Definite assignment checking

Fixed-size buffers are not subject to definite assignment-checking, and fixed-size buffer members are ignored for purposes of definite-assignment checking of struct type variables.

When a fixed-size buffer member is static or the outermost containing struct variable of a fixed-size buffer member is a static variable, an instance variable of a class instance, or an array element, the elements of the fixed-size buffer are automatically initialized to their default values. In all other cases, the initial content of a fixed-size buffer is undefined.