-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Proposal: Fixed-size buffer types #1320
Comments
I'm not a fan of any C# proposal which results in a compiler-generated and named type being exposed publicly. It puts a lot of onus on the specification and the compiler to produce a deterministic name and shape to the type so that existing consumers can't break when the code is recompiled. Aside that, I don't see what this notation buys you. These "structs" can't be passed around. They're useless themselves. They only exist to force the CLR to allocate enough memory to contain the buffer. The buffer itself is managed entirely through unsafe pointer arithmetic and direct memory access. Passing a fixed buffer "by reference" makes no sense. That would be just a pointer. |
I understand your concerns, but this already happens with standard public fixed-sized buffer fields. Their type must be exposed publicly in order to access the field, so the potential risk of breaking the binding doesn't increase. However, now I see that the naming of these types cannot change, so the types of fixed-size buffer fields cannot be shared and must use the same naming convention. I think you misunderstand the semantics of the proposed fixed-size buffer type. Passing it "by reference" makes perfect sense, since without the template <class T, size_t Size>
class fixed
{
T buffer[Size];
}; It's not just Also see the linked proposal, there a way is proposed to map the individual elements of a fixed-size buffer to fields of the compiler-generated struct. I think this makes the type well defined and usable beyond simply a way to allocate memory. If the CLR can move this memory around or reference it in a managed way, why not allow it do so? |
Support this idea. It's just what I want to say. |
@HaloFour Oh yes, I meant to bring up fixed-size buffers in one of our previous conversations as an example of existing public type generation. |
I don't think this is worth doing. It is a fairly niche feature that is basically just shortcutting the need to do Additionally, since it is a value type and would generally result in a "large" struct, it would (from a performance perspective) be expensive unless you always passed/returned using The "workaround" for the lack of this feature is also fairly trivial. It only takes a few lines of code to create a named type which uses a fixed-sized buffer under the hood. The |
Yeah, I wasn't aware that the struct would be made public. Kind of scary as the spec doesn't cover the naming strategy of that struct at all so different compiler implementations could produce incompatible results. IIRC that's the only case where a compiler generated name is leaked publicly like this. |
Duplicate of #1314. |
Seeing the proposed updates to fixed-sized buffers, I have another proposal – the ability to specify a fixed-size buffer on any storage location and therefore effectively introduce fixed-size buffers to the type system.
At the moment, only fields of structs can be fixed-size buffers:
I propose widening this syntax not just to fields, but also to variables with this alternate syntax possible:
This makes buf a variable with type
fixed int[256]
– a new type syntax that refers to the compiler-generated buffer type. In this case, the compiler-generated type looks like this:Instead of a per-field basis, this type would be generated for every combination of type and size used in the code, and would be shared among all variables that are fixed-size buffer with the same base type and size.
A value of a fixed-size buffer type is effectively a by-value array, and passing it would copy all values:
Instead, a reference to a fixed-size buffer variable must be passed in order to modify its values:
Since the fixed-size buffer is now a type, it can also be used as a return value, or as a property:
Creating a new fixed-size buffer this way does not use
stackalloc
, it simply treats the type as a regular value type. Structurally, the typefixed int[3]
is analogous with(int, int, int)
(value tuple syntax). No unsafe memory access has to be performed to move a fixed-size buffer since it is just moving a value type.However, unlike the value tuple type, which is the same in all assemblies, the fixed-size buffer type will be defined for each assembly (module) that uses one. Since all these buffers have the same memory layout, they can be used interchangeably with each other, if an instance of a fixed-size buffer created in the local assembly is to be passed to a method taking a fixed-size buffer (with the same element type and size) defined in a foreign assembly, for example.
In my opinion, fixed-size buffer types go along well with the types already present in C# and are useful in combination with the new .NET memory types (
Span<T>
etc.). They make moving buffers easier and present a compile-time checking of buffer size.The text was updated successfully, but these errors were encountered: