Extend fixed expressions to support more types
Extend fixed expressions to Span, Memory, refs, and GetPinnableReference
There should be some way to pin instances of Span<T>, Memory<T>, and certain kinds of types to take their native addresses for native interop purposes. In C# you can just use the fixed statement, but F# only supports a limited set of constructs, none of which you can get to work with Spans.
This can all be accomplished in F# by making fixed expressions work with anything that implements GetPinnableReference() just like C#.
Pros and Cons
Advantages:
- You can use spans in native interop situations without being forced to copy it to an array first
- Feature parity with C#
Disadvantages:
- It's work
- More special language rules
Extra information
Estimated cost (XS, S, M, L, XL, XXL): M? Just a guess.
Related suggestions: (put links to related suggestions here)
Affidavit (please submit!)
Please tick this by placing a cross in the box:
- [x] This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
- [x] I have searched both open and closed suggestions on this site and believe this is not a duplicate
- [x] This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.
Please tick all that apply:
- [x] This is not a breaking change to the F# language design
- [x] I or my company would be willing to help implement and/or test this
I think this should definitely be allowed.
Come to think of it, fixed should probably also support Memory<'t> directly too.
@cartermp do you think this addition should only concern itself with Span/Memory, or should it be a more general expansion to things that have GetPinnableReference?
FSharp.Core currently doesn't depend on System.Memory. Using statically resolved type parameters with member constraints would be the way to go. Therefore, this should be a more general expansion to things that have GetPinnableReference.
@jwosty We should match what C# does here and lookfor the GetPinnableReference member. @tihan can be of help in figuring out how to determine that.
I support this. This is a very reasonable request.
I say we should also support arbitrary pinning of refs. For example, C# lets you do the following (shamelessly copied from the C# docs):
class Point
{
public int x;
public int y;
}
unsafe private static void ModifyFixedStorage()
{
// Variable pt is a managed variable, subject to garbage collection.
Point pt = new Point();
// Using fixed allows the address of pt members to be taken,
// and "pins" pt so that it is not relocated.
fixed (int* p = &pt.x)
{
*p = 1;
}
}
That way, it's a more general construct that you can use to workaround anything that's not supported directly by fixed, like in that stackoverflow answser I linked to in the OP.
Yup, approved as far as I'm concerned.
@dsyme what do you think about supporting GetPinnableReference vs supporting any ref? Would an RFC be approved if it contained both?
@dsyme what do you think about supporting GetPinnableReference vs supporting any ref? Would an RFC be approved if it contained both?
I don't see why not - @TIHan do you agree?
Here is the csharp pattern based fixed proposal that discusses GetPinnableReference
Based on what I know right now, supporting both sounds very reasonable to me.
Would someone mind drafting up an RFC? I could certainly try but I don't think I have enough knowledge about Span<'T> and the likes (and their inner workings in the C#/F# compilers) to do a good job.
@jwosty, if you want to draft a RFC, we can help you fill in any gaps.
@TIHan great, I will be more than happy to do this once I'm on Christmas break from classes... Can't wait to work on stuff other than school!
PR submitted with a basic, incomplete RFC drafted. Help is now greatly appreciated
Hey @jwosty , awesome that you submitted a draft! When I get some time, I will go over it.
@TIHan not a draft anymore 🙂 https://github.com/fsharp/fslang-design/blob/master/RFCs/FS-1081-extend-fixed-expressions.md
Design discussion here: https://github.com/fsharp/fslang-design/issues/421
would be really nice to see it implemented on par with C# fixed behaviour.
ref pinning is heavily used in Silk.NET and it is currently quite tricky to port their samples to F# without this feature.