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

Usage of StructLayout(LayoutKind.Explicit) #191

Open
HeinzKessler opened this issue Nov 28, 2024 · 2 comments
Open

Usage of StructLayout(LayoutKind.Explicit) #191

HeinzKessler opened this issue Nov 28, 2024 · 2 comments

Comments

@HeinzKessler
Copy link

Suggestion:

A difference between OneOf and C/C++ unions is that with C/C++, a union only uses as much memory as the largest possible field, because all fields overlap in memory.
Since OneOf makes sure that always only one of these fields is valid and in use, such an overlapping structure layout could also be beneficial for OneOf, if memory consumption is a concern.

.Net gives the opportunity to specify the memory layout for the fields of a class or struct. With the StructLayout(LayoutKind.Explicit), all fields could have the same memory address, like in C/C++ unions, by setting FieldOffset of 0, for all of them.

See the documentation of the feature here:
https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.layoutkind?view=netframework-4.8

For the fields to overlap in memory, FieldOffset must be set 0 for all fields in the example.

@emperador-ming
Copy link

This would be awesome!

@StefanLochauMF
Copy link

This seems like a nice thought, but this will likely not work without work of the dotnet-runtime team. The runtime does not allow object fields and non-object fields to overlap. I.e. when loading the instantiation of OneOf<T1, T2> with T1=long and T2=object

[StructLayout(LayoutKind.Explicit)]
public struct OneOf<long, object>
{
   [FieldOffset(0)] public long _value0;
   [FieldOffset(0)] public object _value1;
}

the runtime will throw a TypeLoadException with the message "Could not load type OneOf<...> from assembly '…' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field".

Even

struct ObjectWrapper
{
    public object Object;
}

[StructLayout(LayoutKind.Explicit)]
public struct OneOf<long, ObjectWrapper>
{
   [FieldOffset(0)] public long _value0;
   [FieldOffset(0)] public ObjectWrapper _value1;
}

is not allowed, because recursively the reference in the ObjectWrapper is supposed to be put at the OneOf's index 0. This means even using the where T1 : struct kind of generic restrictions would not help.

I also don't see how one could use C#'s metaprogramming capabilities to compute const indexes depending on the types, so that they handle this gracefully.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants