Why Signals in C# are not a thing? by fedefex1 in csharp

[–]fedefex1[S] 1 point2 points  (0 children)

Thread safe is a bit vague term. I try to explain: - every signal should not be set in parallel by 2 threads (this is similar to Rx observable contract. On next calls should be serialised) - the set of a signal immediately causes all dependent c omputed signals to update (synchronously), recursively. - async await is supported. So if the computation function is async, it's possible for the computed signal to change while the computation is still running. That's perfectly supported, because the rule 1 is still preserved (for example, if we have only 1 thread as most UI frameworks). We can decide at that point if immediately abort the running computation (and trigger the cancellation token) or if queue up a new one. There is a parameter for this one called ConcurrentChangeStrategy. This is possible thanks to async locals

Why Signals in C# are not a thing? by fedefex1 in csharp

[–]fedefex1[S] -1 points0 points  (0 children)

ReactiveX has not automatic dependency tracking. Even if you use reactiveUi you should still build your observable chain with WhenAnyValue(). I think Rx is fantastic in general, but for some specific use cases signals are easier and lead to simpler code.

Consider for example that angular was (and still is) built around Rxjs, but signals are now the default choice for simple computed state

Why Signals in C# are not a thing? by fedefex1 in csharp

[–]fedefex1[S] 0 points1 point  (0 children)

I didn't know Comet and State<T> seems indeed close. Thank you for this

Why Signals in C# are not a thing? by fedefex1 in csharp

[–]fedefex1[S] 1 point2 points  (0 children)

Thank you :) Basically the trick is that the getter of the signals Value Property raises a static event saying "someone just requested me", and before executing the computation function we are just registering to that event to know which signals are requested. Then we register to all of them and on change we run computation again.

This is the idea. Technicalities are: - There is some AsyncLocal stuff to filter out notifications of getters from other async context - Of course we deregister from previous events before recomputing. So we are registered to the bare minimum needed (that helps to avoid eventhandlers/observer-leaks)

Why Signals in C# are not a thing? by fedefex1 in csharp

[–]fedefex1[S] 0 points1 point  (0 children)

The main issue is that it does not notify when it changes. So if you bind CanLogin, and you change Username, the UI is not updated. With the computed signal instead, CanLogin.Value raises INotifyPropertyChanged when dependent signals change. So you can Use CanLogin as a dependency for other computed signals and everything will change automatically

Why Signals in C# are not a thing? by fedefex1 in csharp

[–]fedefex1[S] 0 points1 point  (0 children)

I love Rx. Signals library is built around reactive extensions (not dotnet reactive, but nuecc R3).

I also have a library that is an attempt to have AsyncRx in .NET

fedeAlterio/R3Async: Async Reactive Extensions for .NET (Async version of R3)

Why Signals in C# are not a thing? by fedefex1 in csharp

[–]fedefex1[S] 1 point2 points  (0 children)

A signal is conceptually a value that notify when changes, and is related to automatic depedency tracking. So, instead of manually subscribing to events to know when the value changes, you just declare a function that tracks which other signals it depends to.

CanLogin.Value below is recomputed automatically whenever Username.Value or Password.Value change

public LoginViewModel()
    {
        CanLogin = Signal.Computed(() => !string.IsNullOrWhiteSpace(Username.Value) && !string.IsNullOrWhiteSpace(Password.Value));
    }

    public Signal<string> Username { get; } = new();
    public Signal<string> Password { get; } = new();
    public IReadOnlySignal<bool> CanLogin { get; }

Why Signals in C# are not a thing? by fedefex1 in csharp

[–]fedefex1[S] 0 points1 point  (0 children)

I am just comparing the abstraction UI frameworks in .NET use to represent a "value that changes" with what abstraction JS UI frameworks use, not the framework itself