-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
ReadOnlySpan<T>.DangerousGetPinnableReference should return a readonly reference #23492
ReadOnlySpan<T>.DangerousGetPinnableReference should return a readonly reference #23492
Comments
Agree |
I am not sure whether there is any value in this. We should look at how this method is used. DangerousGetPinnableReference can be really only used together with other unsafe constructs:
|
What is the value in ReadOnlySpan at all if we can mutate with a method so easily? May as well not have the type |
I think there is a lot of value in statically verifying that some data passed by reference to a method is not mutated. However, it seems the way |
@jkotas, can we add readonly ref methods to Unsafe? Without the readonly, users can do the following in safe context: readonlySpan.DangerousGetPinnableReference() = newValue; With readonly, they will have to be in an unsafe context. |
We can. My gut feel is that it is a lot of API clutter with negative value. We need to see how it would work in practice. E.g. rewrite https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/SpanExtensions.cs using readonly refs and ReadOnlySpan.DangerousGetPinnableReference returning readonly ref.
How do you define "unsafe context"? None of this needs C# unsafe keyword with or without this suggestion because C# unsafe keyword is limited to what the C# language considers unsafe. It does not extend to unsafe APIs. DangerousGetPinnableReference is logically unsafe context. If you are using it, you are writing unsafe code. |
Unsafe APIs are important to have. If you have a simple unsafe API, it will be always relatively easy to call. We can make it harder by:
|
For the purpose of this discussion: it's whenever you call APIs on Unsafe class. I totally get that it's not as bullet proof as C# unsafe block, but it might be better than what we have today. |
Isn't the whole point of this method to give me a pointer which is, by definition, not readonly? |
Do we really need the method? Can we have the indexer return Note that right now you would need to cast away |
Basically the following should work (it works with Span, but not with RO span, since indexer returns a value). unsafe class Program
{
static void Main(string[] args)
{
ReadOnlySpan<int> sp = new int[10];
fixed(int * ptr = &sp[0])
{
. . . do stuff with ptr . . .
}
}
} |
IMO, we should:
|
This does not work for spans of Length==0, and has unnecessary range check otherwise. |
@jkotas - I am not sure it should work with Length=0. I think one range check is acceptable when fetching a pointer. It is likely to be very predictable and cheap, possibly even free if can CSE'd with user's check for |
It is intentional that this method works the way it works with
It can return any pointer. It does not have to be 0. It depends on how the Span was created.
Yes, you have to check for emptiness. But you control when and how you do it.
The range check is pretty significant cost when you are fetching the pointer for a very small cheap operation. Consider method like:
If you add range checks to DangerousGetPinnableReference, this method will be significantly slower.
IMHO, it is pretty unfortunate that |
BTW: The idea of changing ReadOnlySpan indexer to return |
Lets change the ReadOnlySpan indexer as it would be a good change on its own. Honestly - An API that allows writing into RO span and has undefined behavior with empty spans is hard to like. Perhaps you are right though and perf penalty is indeed too big to ignore. |
If this method were unsafe I wouldnt care. As written it is completely safe. |
This method is unsafe. It just does not require unsafe C# keyword. |
As I said, it is a safe method on a safe type. |
dotnet/roslyn#22400 has enabled taking unmanaged/pinned addresses of readonly variables. There is no reason for |
We should look at this together:
|
So, what are the next steps for this? #23491 is in progress here and here Do we plan to change DangerousGetPinnableReference to return ref readonly (along with potential rename to GetReference and moving it to MemoryMarshal? cc @stephentoub |
It is still subject to discussions, but it seems reasonable to start changing DangerousGetPinnableReference to be Perhaps change it to return |
@VSadov Breaking changes in signatures of methods that are used in many places are very expensive to push through the system - they need to be staged carefully. @ahsonkhan is still working on changing the indexer to read-only. We should wait for that one to get pushed through first. I think the plan for this one should be:
Doing it this way will avoid the need for complex staging or things being on the floor for extensive periods of time. |
I would hope this change is easier than the indexer. Also |
Yes, it should be easier in the sense that we do not need to do complex staging for it. But it will still require changing hundreds of lines: E.g. out of ~200 calls to DangerousGetPinnableReference in corefx, ~30 of them are used with fixed and should "just work", unless they are performance sensitive and should rather call |
We don't care super much; we see the value in promoting generally safe behavior so the API suggestion looks sensible to me. However, we lack expertise to judge whether this causes clutter (additional casting, like C++ const). So I'd leave it to runtime/compiler folks to decided what to do here. |
FYI: The API review discussion was recorded - see https://youtu.be/BI3iXFT8H7E?t=3414 (6 min duration) |
We may want to just use less ugly |
|
This is about the name that will be used for dotnet/csharplang#1100 . |
Ah, the contract for a |
Should
be
?
That would make it slightly less dangerous.
The text was updated successfully, but these errors were encountered: