[API Proposal]: Transparent layout support for value types.
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
### Background and motivation
Wrapper structs with a single field are popular in many codebases, for SIMD, generics and interop purposes. A common issue with them is that such wrapper types either cause less optimal calling conventions in the 1st case, have issues around wrapping managed types in 2nd, or are not guaranteed to match ABI wise for 3rd.
As such, I'd like to propose exposing support for user defineable value types that guarantee to match the ABI properties of the type they wrap.
This would be enforced both in managed and native calls and would potentially also impact how the JIT treats them for promotion and such.
The runtime would throw `TypeLoadException` if such type contains more than 1 field.
This was previously discussed in #100896 and was left for future discussion AFAIU.
This is already internally implemented in a limited capacity for `CLong`\\`CULong`\\`NFloat`, with public API those could be switched to it from special handling.
For prior art on this, Rust provides this with `#[repr(transparent)]`.
cc @tannergooding @jkoritzinsky @jkotas as you were all involved in previous discussions on this.
### API Proposal
```diff
namespace System.Runtime.InteropServices;
public enum ExtendedLayoutKind
{
+ Transparent
}
```
### API Usage
```csharp
// non interop
[ExtendedLayout(ExtendedLayoutKind.Transparent)]
public readonly struct CustomVector
{
public readonly Vector128 Vector;
}
public static void Method(CustomVector v)
{
// passed via SIMD reg, not stack like normal struct.
}
[ExtendedLayout(ExtendedLayoutKind.Transparent)]
public readonly struct EquatableWrapper : IEquatable>
{
public readonly T Value;
public EquatableWrapper(T value) => Value = value;
public bool Equals(EquatableWrapper other) => EqualityComparer.Default.Equals(Value, other.Value);
// rest of IEquatable
}
// layouts guaranteed to match
Unsafe.BitCast, ReadOnlySpan>>(a).Contains(new EquatableWrapper(o))
// interop
[ExtendedLayout(ExtendedLayoutKind.Transparent)]
public readonly struct Handle
{
public readonly void* Value;
}
// guaranteed to be safe
[DllImport("Kernel32")]
public static extern int CloseHandle(Handle handle);
```
### Alternative Designs
For interop purposes this can be solved with custom LibraryImport marshallers but that doesn't help with blittable PInvokes, function pointers and non interop uses.
### Risks
_No response_
Contributor guide
Research direction
Start with the prior discussion in #100896 and the existing limited handling for CLong, CULong, and NFloat. The issue names no files or tests; the work would need to clarify Transparent layout behavior for managed and native calls, JIT treatment, and the one-field TypeLoadException rule.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend-api-design, compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 28/100