-
Notifications
You must be signed in to change notification settings - Fork 832
Description
Is your feature request related to a problem? Please describe.
Let's say we have a public function foo which uses SRTPs so must be inline. This function has to call a trivial utility function bar that is used from several different parts of the module and does not need to be known outside of the module. Because foo is inline and public, bar has to be public as well, exposing an insignificant implementation detail.
Describe the solution you'd like
If however, bar was private and inline, it could be inlined everywhere foo was used, in a transparent way that does not even imply bar's existence to code outside the module. That's the point of inline functions whatsoever.
Inline functions cannot access constructs with a lower accessibility level than itself, because it would expose hidden code to outsiders. Of course the latter inline function (bar in our case) has to follow that rule despite its accessibility level allowing it. I acknowledge it is kind of counterintuitive.
As for how to implement it, my idea was to keep the reference to toCharacters until the real inlining takes place (when genericUnsigned will be called from a non-inline function). When that happens, the inline functions will have to be recursively expanded.
Describe alternatives you've considered
I can either make bar public but clutter my public API, or manually inline bar's implementation every time it would have been called, but duplicate my code.
Additional context
I am writing a generic high-performance function to parse integers from ReadOnlySpans of characters. In .NET Standard 2.1, I can directly convert the span to an integer without wasting an allocation by converting it to a string first. I abstracted this behavior with a type alias that is a string in all platforms except .NET Standard 2.1 and a function which converts the string to a span in all platforms except .NET Standard 2.1.
type Characters =
// Soon...
#if NETSTANDARD_2_1
ReadOnlySpan<char>
#else
string
#endif
let toCharacters (x: ReadOnlySpan<char>): Characters =
#if NETSTANDARD_2_1
x
#else
x.ToString()
#endifThe following piece of code is used thrice: twice for all types of (un)signed integers, and once for all types of floating-point numbers.
let inline genericUnsigned< ^TInt when ^TInt: (static member Parse: Characters * NumberStyles * IFormatProvider -> ^TInt)> name =
terminal name
(T (fun _ x ->
(^TInt: (static member Parse: Characters * NumberStyles * IFormatProvider -> ^TInt)
(toCharacters x, NumberStyles.Integer, NumberFormatInfo.InvariantInfo))))
unsignedRegexI would like to make the toCharacters function private for obvious reasons.
Update: As I was writing this issue, I realised that there is a similar problem with Characters. Characters is a type alias of a public type, not a new type, so no code will be exposed by inlining the type a bit earlier as well.