Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible inconsistency in BufferMapper exposed properties #28

Open
michi42 opened this issue Nov 14, 2019 · 9 comments
Open

Possible inconsistency in BufferMapper exposed properties #28

michi42 opened this issue Nov 14, 2019 · 9 comments
Assignees
Labels
bug Something isn't working question Further information is requested

Comments

@michi42
Copy link
Member

michi42 commented Nov 14, 2019

Together with Andrea, we found out that the maxSize() property exposed by BufferMapper can be inconsistent if a negative value is set.
In this case, the internal subscriber in BufferMapper will throw, but it will only get the update as soon as any other subscriber gets it - so it cannot refuse it at that point, the value of the property will have been set already.

In such cases, we should use probably use WrapperProperty with an own implementation of set(), that validates, possibly throws, and only then notifies subscriber of a change (if any).

Also, after some more thinking I would be in favor of removing clearTrigger(). In general, I would never expose Observers (only observables and possibly properties) for the same reason I was against introducing "processors" or similar:
It takes the control over the data flow away from the service provider, which then e.g. can not refuse updates. In this case it is probably fine as clear() can not throw and does not care about the data, but if it was some value and not all values were accepted, it would actually create exactly the same problem as with the SimpleProperty for maxSize() above.

@michi42 michi42 added bug Something isn't working question Further information is requested labels Nov 14, 2019
@kaifox
Copy link
Member

kaifox commented Nov 14, 2019

What is the current behaviour, if an observer throws?

@kaifox
Copy link
Member

kaifox commented Nov 14, 2019

Indeed, the clearTrigger() is the same story as the Sink discussion ;-) ... I totally forgot this ;-)

@michi42
Copy link
Member Author

michi42 commented Nov 14, 2019

The current behavior is to not affect other observers or the producer - the exception be caught internally (in DispatchingObservable), wrapped into an UpdateDeliveryException, and sent to the global uncaught exception handler (typically something that would simply log the exception).

Basically observers are not expected to throw.

@kaifox
Copy link
Member

kaifox commented Nov 14, 2019

Lets imagine you do the clearTrigger() by exposing a property:

Property<Object> clear();

And you have somewhere another

Property<Something> triggerInput;

which shall (on any update) clear your buffer.

Ok, then one could of course (assuming we would have implemented binding, which we do not have yet, or?) do something like:

Bindings.bind(clear()).to(triggerInput);

However, what prevents you from then doing

Bindings.bind(clear()).bidirectionally().to(triggerInput);

... and suddenly, any set() on the clear() property would also notify all other subscribers of triggerInput...

My main point is: The clearTrigger() shall only observe. It shall not be observable....
How would you do this...?

With the current implementation it is simply a:

triggerInput.subscribe(clearTrigger());

@kaifox
Copy link
Member

kaifox commented Nov 14, 2019

I think the behaviour you describe above would be ok ...

@kaifox
Copy link
Member

kaifox commented Nov 14, 2019

Ok, what one can do of course always is,

just expose a method void clear();

And then subscribe using a lambda ...

triggerInput.subscribe(() -> clear());

... in the end, you do not listen to exceptions ....

@kaifox
Copy link
Member

kaifox commented Nov 14, 2019

For the maxValue() I agree, this is not clean. Your proposal sounds fine... Could the simple property, potentially just have an additional constructor method (a validator) ...in the simplest case a Consumer that could throw?

@michi42
Copy link
Member Author

michi42 commented Nov 14, 2019

Indeed I would say if you need this behavior, you should build an observer yourself - in the simplest case something like
trigger.subscribe(v -> buffer.clear())
the point is, whoever does this is supposed to have the knowledge of the particularities of the stream he subscribes to, and how exceptions (both from the stream and - if applicable - from buffer.clear()) should be handled.

In general for setting things, I think a wrapperProperty() is the right way to do it. I don't like the fact that the actual change is triggered by a subscription to the property - apart from the problem that there is no way anymore to refuse updates at this point, there is also no guarantee that the change has actually happened at the time the other observers are notified.
I think when exposing a Property is more clean to first apply the changes on set (which can throw) and once it has happened send out a notification to the observers, if any - e.g. using a dispatcher.

@kaifox
Copy link
Member

kaifox commented Nov 14, 2019

For my binding post above, let me reformulate something:

Currently in our concepts we can have (at least in mind) something like

Bindings.bind(a).to(b);

where b can prevent bidirectional binding (by being an ObservableValue). However, a has no way to do so (it always has to be a property ...)

.... I think I have to rethink all this quietly ;-) ... Seems that all this mixing of state/set/bidirectionality is too much for my brain ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants