ParameterState: Call the handler once when parameters reference the same handler.#8384
Conversation
|
This will be automatically applied when lambda expressions will be used too: So I have to warn about when you using lambda instead of the method, because it will optimize when the expression are equals for example: RegisterParameter(nameof(Spacing), () => Spacing, () => _increaseCounter++);
RegisterParameter(nameof(Max), () => Max, () => _increaseCounter++);The increase counter will be called once, when someone might expect that the counter would increase twice, but it will be once. But if you use bools like this RegisterParameter(nameof(Spacing), () => Spacing, () => _childrenNeedUpdates = true);
RegisterParameter(nameof(Max), () => Max, () => _childrenNeedUpdates = true);Then it should be fine, since you don't need to set the same boolean twice. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #8384 +/- ##
==========================================
+ Coverage 88.82% 88.95% +0.13%
==========================================
Files 407 410 +3
Lines 12226 12264 +38
Branches 2441 2451 +10
==========================================
+ Hits 10860 10910 +50
+ Misses 834 826 -8
+ Partials 532 528 -4 ☔ View full report in Codecov by Sentry. |
|
at 4am got an enlightenment.... var parameterChangeShouldFire = new HashSet<ParameterMetadata>(ParameterHandlerUniquenessComparer.Default);
var changedParams = _parameters.Where(parameter => parameter.HasHandler && parameter.HasParameterChanged(parameters)).ToList();
await baseSetParametersAsync(parameters);
foreach (var changedParam in changedParams)
{
if (parameterChangeShouldFire.Add(changedParam.Metadata))
{
await changedParam.ParameterChangeHandleAsync();
}
}Which works great, but I can just do: #if NET8_0_OR_GREATER
var parametersHandlerShouldFire = _parameters
.Where(parameter => parameter.HasHandler && parameter.HasParameterChanged(parameters))
.ToFrozenSet(ParameterHandlerUniquenessComparer.Default);
#else
var parametersHandlerShouldFire = _parameters
.Where(parameter => parameter.HasHandler && parameter.HasParameterChanged(parameters))
.ToHashSet(ParameterHandlerUniquenessComparer.Default);
#endif
await baseSetParametersAsync(parameters);
foreach (var parameterHandlerShouldFire in parametersHandlerShouldFire)
{
await parameterHandlerShouldFire.ParameterChangeHandleAsync();
}With extending the |
Oh and if you will do RegisterParameter(nameof(Spacing), () => Spacing, OnParameterChanged());
RegisterParameter(nameof(Max), () => Max, () => OnParameterChanged());This will also be considered different, but I think it's all fine compromises considering that this string expressions are generated at compilation, we could just cover this with documentation. After all if we really need we could trim it down with regex in future, |
|
Yes, passing an anonymous func calling the handler method |
This would indeed be quite unexpected. Maybe we only optimize when a method group is passed? We can recognize anonymous functions because they contain |
Yeah, we can add this to "exclusion rule" if you'd like |
|
updated the code |
|
I'll add a test for the lambda exception in the afternoon |
|
Thanks for the bUnit tests, I was kind of lazy to do them 😭. |
|
Wait you can use when there is actually no [Parameter]
public EventCallback<int> AChanged { get; set; }? |
|
Hmm, you are right, there is no need to use |
No worries, I did promise to contribute the tests |
Oh don't worry, u can leave as it. |
|
Do we merge? I don't think I have anything to add. |
|
I think it's ready to merge |
Unfortunately, using a Frozenset on .NET 8 on IOS (for a maui hybrid app), makes the application crash atm when using AOT in combination with the interpreter. Until this is fixed, I'd propose using the normal hashset for .NET 8 as well. see: CommunityToolkit/Maui#1752 (comment) The workaround mentioned in this thread unfortunately makes the app crash completely. |
|
Hi
That's very unfortunate and big surprise that it's not working even with interpreter. Tho I have a question, have people tried only: <PropertyGroup Condition="$(Configuration.Contains('Release')) And $(TargetFramework.Contains('ios'))">
<MtouchInterpreter>-all,System.Collections.Immutable</MtouchInterpreter>
</PropertyGroup>but not: <MtouchLink>SdkOnly</MtouchLink>
<UseInterpreter>True</UseInterpreter>? |
If people will report this is working for them, I will probably not change to normal |
|
However, I can now attest that it is the combination of UseInterpreter and that makes it fail. I did not have the conditions included. UseInterpreter is default in Debug builds, but not in Release builds. So this statement works (both in debug and in release): However this causes a crash: and this causes an exception (InvalidCastException) |
What are the performance regression except the startup? I'm sorry, but I cannot imagine full AOT to be prod ready in MAUI for now, more drawbacks than benefits. Once you start to use reflection, expression etc you will need to use
Great, I think you should share it in the |
UseInterpreter enables the interpreter and disables AOT compilation. Since iOS cannot JIT compile, this means that the entire application will be interpreted. MtouchInterpreter will enable the interpreter for iOS only, and in addition will still allow AOT compilation. the -all indicates that all assemblies will be AOT compiled. System.Collection.Immutable will be interpreted (since it does not have the - in front of it.
see also: |


Description
Helps to optimize this case: #8381
I think this is the best solution as we do not use any reflection, which is very important when amount of components and variables increase with the
ParameterState, it could create a bottleneck.How Has This Been Tested?
New unit tests.
Visual, at least that we didn't break the existing components that use
ParameterStateTypes of changes
Checklist:
dev).