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
Crazy idea: Unsafe C# extensions #2011
Conversation
These look awesome to me. 👍 |
Looks very interesting, what is the purpose though of getting a pointer to an object on the heap? |
Is this comparable to or the same as this? |
@dorianmuthig not really, the functionality you show is the default unsafe functionality. This is an addition on top, usually in C# you can get pointers only to blittable types. |
Loved it. Specially "Pointers can be used in generic type arguments" |
Me and @ddobrev have been discussing the usefulness of these for CppSharp. We could use these features to improve the generated bindings in some places but unfortunately we won't be able to because of our compatibility to .NET. Still nice work on this, I'd like to see these getting in to allow for further experimentation. |
The LLVM example is one use case. What it's doing can't be expressed in C# today.
The thing is, if this is added as an extension and it turns out people find this useful in practice, we could probably push for standardization with Microsoft. Ecma 335 even states that pointers not being allowed in generics is merely an arbitrary limitation. |
If this is pushed to ECMA, I am all for. I am afraid though that up until then we cannot use it even just on Mono because there would be a difference in the API. We do need to provide different binding assemblies per OS anyway but our API can and must be the same. |
Someone else (Alexandre Mutel) has been playing with some similar extensions for CoreCLR and Roslyn. http://xoofx.com/blog/2015/09/27/struct-inheritance-in-csharp-with-roslyn-and-coreclr/ |
is there still interest to merge this or should it be closed? |
I think that's a @marek-safar question. I believe he was looking into how an extension like this could be integrated neatly? |
@alexrp, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR. |
@alexrp, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR. |
Since we're probably switching to Roslyn in the near future, I'll close this. |
This is a quite possibly insane idea that came to mind over the weekend and was fairly easy to hack into
mcs
. This patch adds a newunsafe
language version (i.e.-langversion:unsafe
) tomcs
which impliesexperimental
and enables the following extensions:int i = 42; List<int*> list; list.Add (&i);
)string s = "..."; string* p = &s;
)stackalloc
declarations. (string* strings = stackalloc string [16];
)var sz = sizeof (string); /* 4 or 8 */
)All of these still require
unsafe
context. Also, there is no guarantee that the generated code will work with any other VM.Pointers in generic type arguments
This one is interesting because it adds type safety that C# doesn't currently have when dealing with pointers in collections. Today, you have to maintain a
List<IntPtr>
which is not really any better thanList<object>
in terms of type safety.Today, you do:
If the type of
i
ever changes, you likely won't notice that you're now putting mistyped pointers intoptrs
.With the extension:
Pointers to managed objects
This is a simple but surprisingly useful feature. It's as unsafe as any other kind of pointer, but when used with care can allow some patterns that are currently impossible in C# due to the restrictive nature of
ref
andout
.LLVM's instruction matching framework is one example of where this feature can be really useful. They have this code in
lib/Transforms/InstCombine/InstCombineAddSub.cpp
:What happens here is that
A
andB
are stored into temporary structures by reference via them_...
calls which set up match specifications. They are then set once thematch
call goes through the matching tree and callsmatch
on each node. If the whole match passes,A
andB
have been set to the desired values from the instruction tree.This can't really be done reasonably in C# with
ref
/out
as these references can't be stored into fields. It can't be done with pointers currently, either, as pointers can only point to things that don't contain managed references, which is highly restrictive and impractical.This change enables the above.
Managed types in
stackalloc
declarationsThis quite simply allows the following:
That is, managed references can be stored in
stackalloc
'd memory, as can structures containing managed references. I suspect the latter case will be the most useful one in practice.Note that this relies entirely on Mono doing stack scanning conservatively for managed stack frames. If that ever changes, this won't work, and for that reason I'm not really convinced this is as worthwhile an idea as the other features. On the other hand, even a stack-precise Mono could scan
stackalloc
'd memory conservatively to enable this feature. Who knows.Size of managed references
This is a small feature that makes the above features really come together.
Marshal.SizeOf
has all sorts of special cases and only sometimes does what the user wants.sizeof
will now simply do what you'd expect for any type: Return the size of storing that type in memory. For structures, this means the size of all its fields as the runtime sees it, while for references, this means the size of a managed reference. No special cases where certain types are not allowed.This means that unsafe code that computes sizes of types will be clearer and more maintainable.
TL;DR
This off-by-default extension enables more practical and 'safe' unsafe programming in C# but generates code that won't necessarily work in other VMs. Useful enough to merge? I don't know. But I could see myself using these features in some tools that aren't intended to run anywhere but on Mono.