Avoid allocations when chaining contexts #2613
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
ba6028b:
#2607 added chaining of nested contexts.
It always creates a new
Lazy<string>
but we do allow a nullContext
fluentassertions/Src/FluentAssertions/Execution/AssertionScope.cs
Line 316 in e760ba4
So if both context are null, we can then then avoid creating a new context.
Also if one of the contexts are null, we can just return the other one.
Now we only need to create a new context in the last case where we have two non-null contexts.
As the lambda passed to the new
Lazy<string>
takes a closure over the other contexts, one needs to take some care to avoid always allocating the closure object.See how Bar is the only variant that is non-allocating when either contexts are null.
code
694ca94:
In #1939 (comment) I avoided allocating a new lambda closure object per iteration using, by creating a
Func
outside the loop, which the compiler sees at non-capturing and then allocates at most in a static field.We can improve this by utilizing local functions, which is also marked as static to enforce it doesn't take any closure.
Inspect the lowered code in SharpLab to see the differences between using a lambda directly inside the loop, creating a
Func
outside the loop and now using a static local function.Benchmarking:
code
IMPORTANT
./build.sh --target spellcheck
or.\build.ps1 --target spellcheck
before pushing and check the good outcome