-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Background and motivation
It is always safe to convert a ReadOnlySpan<U> to a ReadOnlySpan<T> when U inherits from T (and neither are value types). However, performing such a cast is remarkably ugly and requires unsafe APIs:
public static ReadOnlySpan<object> FromStrings(ReadOnlySpan<string> stringSpan)
=> MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<string, object>(ref MemoryMarshal.GetReference(stringSpan)), stringSpan.Length); A safe and easy-to-use API can be provided for performing such conversions.
API Proposal
namespace System;
public ref struct ReadOnlySpan<T>
{
public static ReadOnlySpan<T> CastUp<TDerived>(ReadOnlySpan<TDerived> items) where TDerived : class, T;
}There is prior art in ImmutableArray.CastUp which I have followed in this proposal.
API Usage
public static ReadOnlySpan<object> FromStrings(ReadOnlySpan<string> stringSpan)
=> ReadOnlySpan<object>.CastUp(stringSpan);Alternative Designs
The method could be provided on MemoryExtensions as an extension method.
namespace System;
public static class MemoryExtensions
{
// <T, TDerived> or <TDerived, T>?
public static ReadOnlySpan<T> CastUp<T, TDerived>(this ReadOnlySpan<TDerived> items) where TDerived : class, T
}However, type inference would not be possible for the type parameters:
public static ReadOnlySpan<object> FromStrings(ReadOnlySpan<string> stringSpan)
=> stringSpan.CastUp<object, string>(stringSpan);It could be confusing to remember whether T or TDerived comes first in the generic type argument list.
This would be inconsistent with the existing ImmutableArray API. The difference is purely aesthetic, and presumably the ergonomic tradeoffs were considered during the review of that API, so sticking with the prior art seems best.
Risks
No response