Skip to content

[API Proposal]: update API signatures to leverage ref readonly parameters #85911

Closed
@Sergio0694

Description

@Sergio0694

Background and motivation

Note: supersedes #73608.

This issue tracks updating the signatures of all methods that can benefit from either the new ref readonly parameters (see dotnet/csharplang#6010), as well as the additional flexibility from the compiler allowing changes in ref-ness for method parameters without it being a breaking change (also see speclet at dotnet/csharplang#7165). Needs Roslyn changes first.

API Proposal

namespace System
{
    public static class Nullable
    {
-       public static ref readonly T GetValueRefOrDefaultRef<T>(in T? nullable) where T : struct;
+       public static ref readonly T GetValueRefOrDefaultRef<T>(ref readonly T? nullable) where T : struct;
    }

    public readonly ref struct ReadOnlySpan<T>
    {
-       public ReadOnlySpan(in T reference);
+       public ReadOnlySpan(ref readonly T reference);
    }
}

namespace System.Runtime.CompilerServices
{
    public static class Unsafe
    {
-       public static bool AreSame<T>(ref T left, ref T right);
+       public static bool AreSame<T>(ref readonly T left, ref readonly T right);
-       public static ref T AsRef<T>(in T source);
+       public static ref T AsRef<T>(ref readonly T source);
-       public static nint ByteOffset<T>(ref T origin, ref T target);
+       public static nint ByteOffset<T>(ref readonly T origin, ref readonly T target);
-       public static void Copy<T>(void* destination, ref T source);
+       public static void Copy<T>(void* destination, ref readonly T source);
-       public static void CopyBlock(ref byte destination, ref byte source, uint byteCount);
+       public static void CopyBlock(ref byte destination, ref readonly byte source, uint byteCount);
-       public static void CopyBlockUnaligned(ref byte destination, ref byte source, uint byteCount);
+       public static void CopyBlockUnaligned(ref byte destination, ref readonly byte source, uint byteCount);
-       public static bool IsAddressGreaterThan<T>(ref T left, ref T right);
+       public static bool IsAddressGreaterThan<T>(ref readonly T left, ref readonly T right);
-       public static bool IsAddressLessThan<T>(ref T left, ref T right);
+       public static bool IsAddressLessThan<T>(ref readonly T left, ref readonly T right);
-       public static bool IsNullRef<T>(ref T source);
+       public static bool IsNullRef<T>(ref readonly T source);
-       public static T ReadUnaligned<T>(ref byte source);
+       public static T ReadUnaligned<T>(ref readonly byte source);
    }
}

namespace namespace System.Runtime.InteropServices
{
    public static class Marshal
    {
-       public static int QueryInterface(IntPtr pUnk, ref Guid iid, out IntPtr ppv);
+       public static int QueryInterface(IntPtr pUnk, in Guid iid, out IntPtr ppv);
    }

    public static class MemoryMarshal
    {
-       public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref T reference, int length);
+       public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref readonly T reference, int length);
-       public static unsafe void Write<T>(Span<byte> destination, ref T value) where T : struct;
+       public static unsafe void Write<T>(Span<byte> destination, in T value) where T : struct;
-       public static unsafe bool TryWrite<T>(Span<byte> destination, ref T value) where T : struct;
+       public static unsafe bool TryWrite<T>(Span<byte> destination, in T value) where T : struct;
    }
}

namespace System.Threading
{
    public static class Volatile
    {
-       public static bool Read(ref bool location);
+       public static bool Read(ref readonly bool location);
-       public static byte Read(ref byte location);
+       public static byte Read(ref readonly byte location);
-       public static double Read(ref double location);
+       public static double Read(ref readonly double location);
-       public static short Read(ref short location);
+       public static short Read(ref readonly short location);
-       public static int Read(ref int location);
+       public static int Read(ref readonly int location);
-       public static long Read(ref long location);
+       public static long Read(ref readonly long location);
-       public static IntPtr Read(ref IntPtr location);
+       public static IntPtr Read(ref readonly IntPtr location);
-       public static sbyte Read(ref sbyte location);
+       public static sbyte Read(ref readonly sbyte location);
-       public static float Read(ref float location);
+       public static float Read(ref readonly float location);
-       public static ushort Read(ref ushort location);
+       public static ushort Read(ref readonly ushort location);
-       public static uint Read(ref uint location);
+       public static uint Read(ref readonly uint location);
-       public static ulong Read(ref ulong location);
+       public static ulong Read(ref readonly ulong location);
-       public static UIntPtr Read(ref UIntPtr location);
+       public static UIntPtr Read(ref readonly UIntPtr location);
-       public static T Read<T>(ref T location) where T : class?;
+       public static T Read<T>(ref readonly T location) where T : class?;
    }

    public static class Interlocked
    {
-       public static ulong Read(ref ulong location);
+       public static ulong Read(ref readonly ulong location);
-       public static long Read(ref long location);
+       public static long Read(ref readonly long location);
    }
}

namespace System.Numerics
{
    public static class Vector
    {
-       public static Vector<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }
}

namespace System.Runtime.Intrinsics
{
    public static class Vector64
    {
-       public static Vector64<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector64<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector64<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector64<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector128
    {
-       public static Vector128<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector128<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector128<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector128<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector256
    {
-       public static Vector256<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector256<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector256<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector256<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector512
    {
-       public static Vector512<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector512<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector512<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector512<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }
}

API Usage

For instance, easy QI with immediate values:

IntPtr pUnknown = GetPtr();

Marshal.ThrowExceptionForHR(Marshal.QueryInterface(pUnknown, new Guid("3718BE5F-F5A1-40CF-AF09-C4ECFD858A47"), out IntPtr pObject));

Or, writing immediates into spans:

Span<byte> bytes = GetSpan();

MemoryMarshal.Write(bytes, 128UL);

Or, loading vectors from readonly spans directly:

ReadOnlySpan<int> span = GetSpan();

Vector128<int> vector = Vector128.LoadUnsafe(in span[0]);

There's of course lots more examples (see API changes above).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions