Skip to content

[API Proposal]: Replace TFrom : struct constraint on Unsafe.BitCast with a dynamic check #99205

@MihaZupan

Description

@MihaZupan

Background and motivation

In .NET 8 we've added the Unsafe.BitCast API as a less-unsafe alternative to Unsafe.As when casting between compatible structs.

One justification was that this would let us avoid codegen pessimization for values marked as address-taken in some cases. Example from the original API proposal: #81334 (comment)

Due to the TFrom : struct constraint, we can't use this API in places like the span.IndexOf* helpers.
I propose we drop the generic constraint while keeping the runtime behavior the same.

With the constraint removed, I was able to confirm that we're able to flow the constness of values through for this case: MihaZupan@65c8054.

Quoting the conclusion from the initial API review:

... we should try having it constrained, and if we run into problems then get rid of them. They're easier to remove than add.

API Proposal

namespace System.Runtime.CompilerServices;

public static class Unsafe
{
    public static TTo BitCast<TFrom, TTo>(TFrom value)
-       where TFrom : struct
        where TTo : struct;
}

API Usage

public static unsafe int IndexOf<T>(this Span<T> span, T value)
    where T : IEquatable<T>?
{
    if (RuntimeHelpers.IsBitwiseEquatable<T>() && sizeof(T) == sizeof(short))
    {
        return IndexOfValueType(
            ref Unsafe.As<T, short>(ref MemoryMarshal.GetReference(span)),
            Unsafe.BitCast<T, short>(value0), // <--- This is now legal
            span.Length);
    }

    // ...
}

private static unsafe int IndexOfValueType<T>(ref T searchSpace, T value, int length)
    where T : struct, INumber<T> => 42;

Alternative Designs

We could drop the constraint on TTo as well while we're at it?

Risks

Some erroneous usages move from being compile-time errors to run-time exceptions.
But this is an Unsafe API for a reason :)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions