Skip to content

Commit 3fbb5ee

Browse files
committed
Add comment about delegate allocations
1 parent c3bf73b commit 3fbb5ee

1 file changed

Lines changed: 28 additions & 1 deletion

File tree

FormatWith/Internal/FormatWithMethods.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,35 @@ public static void FormatWith(
156156
{
157157
if (formatString.Length == 0) return;
158158

159-
// TODO: We can avoid internal delegate/closure allocations once function pointers are implemented:
159+
// A note on delegates:
160+
//
161+
// We currently have three delegate allocations per FormatWith call, the handlerAction, the resultAction, and the Tokenizer callback.
162+
// This only happens once per FormatWith call but it is less than ideal if we're attempting to be as low allocation as possible.
163+
//
164+
// NOTE: Need to investigate if any of these are cached by the compiler.
165+
//
166+
// 1. A lambda expression which doesn't capture any variables is cached statically
167+
// 2. A lambda expression which only captures "this" could be captured on a per-instance basis, but isn't
168+
// 3. A lambda expression which captures a local variable can't be cached
169+
//
170+
// TODO: These are some potential workarounds to eliminate these allocations:
171+
//
172+
// 1. resultAction could be eliminated in the internal case where we have a StringBuilder. We could pass the StringBuilder reference in and call Append() on it directly.
173+
//
174+
// 2. ForEachToken could be eliminated by moving all possible variations of the callback into the Tokenizer code directly, and then passing in an enum
175+
// and all state variables, keeping everything on the stack.
176+
//
177+
// 3. handlerAction could be eliminated by moving the internal variations into ProcessToken along with an enum and all state variables.
178+
//
179+
// None of these are ideal but will be necessary unless the compiler/JIT gets a lot smarter about inlining and eliminates these delegates in internal cases.
180+
//
181+
// Function pointers, once implemented, may provide a solution to delegate allocation (albeit with unsafe code):
160182
// https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/function-pointers.md
183+
//
184+
// See also:
185+
// https://devblogs.microsoft.com/premier-developer/dissecting-the-local-functions-in-c-7/
186+
//
187+
161188
void ForEachToken(FormatToken token) => FormatHelpers.ProcessToken(token, handlerAction, resultAction, missingKeyBehaviour, fallbackReplacementAction);
162189

163190
Tokenizer.Tokenize(formatString, ForEachToken, openBraceChar, closeBraceChar);

0 commit comments

Comments
 (0)