Replies: 2 comments 1 reply
-
We (the current maintainers of Rx.NET) didn't actually reject it. The person who proposed it closed their own PR before we even saw it! (It was only open for 2 days.) It's possible that this was because they felt discouraged by the feedback in that thread (which came from Rx community members, not active maintainers). We never spent much time thinking about this proposal because the proposer had already closed it by the time we got to it. Had the issue still been open, I would have wanted to better understand the use cases. The proposal came in the form of code without much explanation, which leaves me to try and guess why the author of the PR thought it would be valuable. As far as I can tell, the basic idea here is that the concept of a reactive read-only property is useful enough that we should consider defining an interface to represent this. The fundamental idea of an
If I'm correctly understanding your statement that it would be:
I think (I'm guessing here) the argument would be that people are already exposing properties of type If that's what you're thinking, then I can see the argument that this makes it easier to achieve better encapsulation and safer design. I have been unable to guess what the argument is that this would improve "decomposition". In fact, composability appears to be the weak point of this design. As was already noted in the feedback on the original PR, as soon as you start using this type's That's not a showstopper. It just means that this type would need to be understood as a kind of 'terminal' type, in the sense that it can only have anything to offer when it is the last (or only) thing in an observable chain. One question I have is: how much value does this really add? Today you can write something like this: public class WithObservableProperty
{
private readonly BehaviourSubject<int> _numbers;
public IObservable<int> Numbers => _numbers;
public int CurrentNumber => _numbers.Value;
} The upside of the public class WithObservableProperty
{
private readonly BehaviourSubject<int> _numbers;
public IBehaviorObservable<int> Numbers => _numbers;
} But the consumption model seems slightly clunkier with int currentValue = mySource.CurrentNumber; and here's how it looks with the proposed int currentValue = mySource.Numbers.Value; So while you've saved yourself a line of code on the implementation side, the consumer side gets slightly more complex. On the other hand, I can see there is some benefit in the fact that the relationship between the event stream and the current value is explicit: it's clear when we retrieve So here's where I'm at. I don't agree with the comment on #1961 that said this "makes no sense." That comment seems to be based on the fact that the 'behaviorness' will not propagate through standard Rx operators such as (Actually, in principle you could define more specialized extension methods so that it did flow like this. But it would only make sense for certain operators. It would not make sense for I also don't think that the comment on #1961 stating that this should be solved at the language level is correct. For one thing, that refers to a proposed part of the extensions feature that 's coming in C# 14 which has, as I understand it, been dropped. (It was a stretch goal.) It wasn't clear to me how that feature would have helped here, but that's academic because the feature ("Adaptation to Interfaces") isn't going to be part of the Extensions feature in C# 14, and isn't going to happen in the foreseeable future. On the negative side, I'm not yet convinced that the value justifies the addition of a whole new abstraction. (I'm not saying that I'm convinced that the value is not there either. I'm just that I've not seen enough evidence to convince me either way.) Some people have asserted that this would be valuable, but have not supplied strong supporting arguments or evidence. Also, there is something that troubles me slightly about this. The basic design of Rx builds on simple ideas backed by mathematics. It's easy to use Rx without knowing anything about this, but the mathematical underpinnings are the secret behind Rx's composability. The composition works so effortlessly that we don't often think about it but it's no happy accident: composition is at the very heart of Rx's core abstractions. From this perspective, Because of this I would expect that So while it might be convenient, it's conceptually flaky compare to other Rx abstractions, which makes me wary of it. That's not a "no". It's a mark against it. It's the reason I would want to see the case in favour providing evidence, and concrete arguments to support the assertions being made in its favour. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the response! I can see that your application design has got value from this abstraction. But you were able to get that value without needing the definition to live in As far as I can tell, the main upside in these cases would have been that you wouldn't have needed to define the interface yourself, and you wouldn't have needed to write an adapter for Since it was possible for you to realise the gains of this abstraction despite the fact that
Regarding 1, you said this:
I did search GitHub for If it were extremely common for people to write their own version of this, then that would certainly support the case for adding it to But 2 is also important: are there scenarios that are blocked today as a result of there being no single, shared definition of this abstraction? Sometimes, a central definition of an abstraction can unlock potential. But as far as I can see, the examples you gave all worked well despite the absence of a single shared definition. This suggests that the added value from a central definition would be very small here. (It would essentially just enable you to remove the interface definition and one simple adapter class.) As far as I can tell, ReactiveUI and DynamicData don't introduce interfaces to represent this concept. Are you aware of there being any scenarios they would like to support that would be enabled by a common definition of this abstraction? In a discussion around this very idea in the Rx slack discussion back in 2023 (prompted by the very PR you link to), one of the RxUI people observed that "RxUI ViewModel properties are all effectively hidden BehaviorSubjects" (although as far as I can see, they don't actually use I get that in theory, a common interface would make it possible to write code that could consume implementations of this from multiple libraries. But I don't yet see any specific scenarios in which this would actually be useful. You made this suggestion:
This actually highlights my concerns about the soundness of the abstraction. You perceive this as a "safe" optimization, but my first thought is that this defeats an important expectation that observable sources can normally rely on: So it's only safe if all implementors of this new interface understand that they can no longer rely on being treated as first class I would be uncomfortable about an essential LINQ operator changing something quite so fundamental for certain particular kinds of observables. It does suggest that this abstraction isn't really an Obviously this has all been on the negative side, but to clarify, this still isn't a "no". One thing could reverse my position: a compelling practical example showing something that can be achieved if and only if this abstraction is shared. (It would need to be compelling enough to overcome my concerns about implementors not enjoying standard |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
In PR #1961, this idea was rejected — but I still think it was a great one.
In my own projects, I often end up creating a proxy class like ReadOnlyBehaviorSubject (similar in concept to ReadOnlyCollection).
Introducing a formal interface for this pattern would be a big win for decomposition, encapsulation, and safer design.
Beta Was this translation helpful? Give feedback.
All reactions