Overview
I want generic extension methods with this in T parameter to compile.
The spec explicitly disallows this usage:
"On the other hand in extension methods exist specifically to reduce implicit copying. However any use of an in T parameter will have to be done through an interface member. Since all interface members are considered mutating, any such use would require a copy. - Instead of reducing copying, the effect would be the opposite. Therefore in this T is not allowed when T is a generic type parameter regardless of constraints."
But not every use of an in T parameter will have to be done through an interface member.
- It could be used by another generic method with
in T parameter.
- It can be finally consumed by an
Unsafe.SizeOf<T>() or Unsafe.AsRef<T>() and converted to a managed pointer, which does not require any struct copy.
Motivation
I have implemented an arbitrary precision floating point library designed for floats from 16 bytes up to a few hundred kbytes. The various floats are defined by a struct of desired size which must only implement the empty interface IFpFloatReadonlyStruct. No struct methods are implemented directly (beside a ToString() override).
All float structs share the same generic library code.
The core functioniality is implemented in only 3 extension methods based on
static uint GetStructSizeInSlots<TFloat>(ref TFloat number) where TFloat : struct, IFpFloatReadonlyStruct {..}
static ref readonly uint GetLead<TFloat>(ref TFloat number) where TFloat : struct, IFpFloatReadonlyStruct {..}
static ref readonly uint FractionAt<TFloat>(ref TFloat number, int index) where TFloat : struct, IFpFloatReadonlyStruct {..}
These three base methods are using managed pointer API similar to the System.Runtime.CompilerServcies.Unsafe class.
These base methods are consumed by higher level arithmetic functions like Add(), Multiply(), Log() and so on.
The JIT compiler really does an incredible good job with function inlining and generic code expansion.
Unintended struct copy does not occure during this usage. But any compiler warning - when doing so - would be strongly wellcomed!
Problem
At the moment every in TFloat argument passing is done by using ref.
But using ref instead of in has following drawbacks:
- the per design readonly input arguments can be assigned and therefore accidentially changed
- cannot be used with readonly 'constants' (readonly fields or ref readonly returning properties / methods)
Current Behavior
Compiling
public interface IFpFloatReadonlyStruct { /*empty*/ }
public readonly struct FpFloatStruct256 : IFpFloatReadonlyStruct {
...
}
public static class FpFloatStruct {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref readonly uint FractionAt<TFloat>(this in TFloat number, int index)
where TFloat : struct, IFpFloatReadonlyStruct {
return ref Unsafe.Add(ref Unsafe.As<TFloat, uint>(ref Unsafe.AsRef(number)), index + 1);
}
}
raises following error at the function definition
CS8338: The first parameter of an 'in' extension method 'FractionAt' must be a value type.
Desired Behavior
The above code compiles.
Breaking Change
No, because currently this is an error.
But a compiler warning - when unintential struct copy occurs - is strongly recommended.
Remarks
I can supply more detailed examples and use cases, when desired.
Please consider a change.
BR Gerhard
Overview
I want generic extension methods with
this in Tparameter to compile.The spec explicitly disallows this usage:
"On the other hand
inextension methods exist specifically to reduce implicit copying. However any use of anin Tparameter will have to be done through an interface member. Since all interface members are considered mutating, any such use would require a copy. - Instead of reducing copying, the effect would be the opposite. Therefore inthis Tis not allowed whenTis a generic type parameter regardless of constraints."But not every use of an
in Tparameter will have to be done through an interface member.in Tparameter.Unsafe.SizeOf<T>()orUnsafe.AsRef<T>()and converted to a managed pointer, which does not require any struct copy.Motivation
I have implemented an arbitrary precision floating point library designed for floats from 16 bytes up to a few hundred kbytes. The various floats are defined by a struct of desired size which must only implement the empty interface
IFpFloatReadonlyStruct. No struct methods are implemented directly (beside aToString()override).All float structs share the same generic library code.
The core functioniality is implemented in only 3 extension methods based on
These three base methods are using managed pointer API similar to the
System.Runtime.CompilerServcies.Unsafeclass.These base methods are consumed by higher level arithmetic functions like Add(), Multiply(), Log() and so on.
The JIT compiler really does an incredible good job with function inlining and generic code expansion.
Unintended struct copy does not occure during this usage. But any compiler warning - when doing so - would be strongly wellcomed!
Problem
At the moment every
in TFloatargument passing is done by usingref.But using
refinstead ofinhas following drawbacks:Current Behavior
Compiling
raises following error at the function definition
Desired Behavior
The above code compiles.
Breaking Change
No, because currently this is an error.
But a compiler warning - when unintential struct copy occurs - is strongly recommended.
Remarks
I can supply more detailed examples and use cases, when desired.
Please consider a change.
BR Gerhard