Community
Participate
Working Groups
The case is a bit hard to describe and reproduce, but maybe one has still some idea what cause this and how to fix it. I have a WritableValue<Person> info = new WritableValue<>(); this object is updated by a user selection (a list of Persons). I bind the values using SWT in two way: ISWTObservableValue<String> nameField = WidgetProperties.text(SWT.Modify).observe(nameTextField)); IObservableValue<String> infoName = PojoProperties.value("name", String.class).observeDetail(info); factory.create(nameField::getValue, infoName::setValue); factory.create(info::getValue, v -> { if(v == null) { nameField.setValue(""); } else { nameField.setValue(v.getName()); } }); Everything works fine (when I change the info object the textfield gets updated, when I change the text my object gets updated). But when I change the value of "info" fast enough (e.g. user clicks fast or uses up/down arrows repeatably) things blow-up and values are getting overwritten (e.g. suddenly the second entry in the list gets the same value as the first entry). I can avoid this by pausing all sideefects, set the info value and then resume in an async callback but this is of course not desirable.
Hello, Christoph Can you attach a minimal, runnable code example that demonstrates the problem?
Sadly I was not able to reproduce this yet with a minimal example and I have no idea what can causing this beside the example describing the problem. I observed this under Linux+Windows so it seems not to be related to the OS...
I played around a bit to find an example an came to the conclusion that this might be some kind of "race-condition" lets stick with the example: ISWTObservableValue<String> nameField = WidgetProperties.text(SWT.Modify).observe(nameTextField); IObservableValue<String> infoName = PojoProperties.value("name", String.class).observeDetail(info); factory.create(nameField::getValue, infoName::setValue); Lets say the text changes, then a change event is generate from the 'nameField' property. Once in a while this will be propagated to the 'info' object through the factory binding, but it seems some things are done in sync and some async so there is a chance of getting hold on a wrong state.
(In reply to Christoph Laeubrich from comment #3) > I played around a bit to find an example an came to the conclusion that this > might be some kind of "race-condition" On your explanation it sounds like it might be a race. The flaky symptoms and the different results on different OS:s suggest that. Question: In the problematic code, is there multiple threads involved? Do you update observables on a background thread, and use the databinding framework to propagate the data to the SWT main thread? If only a single thread is involved then everything in the databinding framework should happen synchronously and you should see such flaky results.
(In reply to Jens Lideström from comment #4) > If only a single thread is involved then everything in the databinding > framework should happen synchronously and you should see such flaky results. That is not completely true. While in a single-threaded case (what is the case here) there is no concurrency there still race conditions can happen if a shared mutable state is accessed. In this particular case, take a look at org.eclipse.core.internal.databinding.observable.sideeffect.SideEffect.scheduleUpdate() this uses realm.asyncExec what describes as > Causes the <code>run()</code> method of the runnable > to be invoked from within this realm at the next > reasonable opportunity. That mean it is run synchronous in the realm but with no control of the time, and it explicitly states: > The caller of this method continues to run in parallel that means that even calling it from inside the realm does not make it happen instantly. So it heavily depends on the order and how the update is performed. e.g. SideEffects are executed after all (or some) other events are executed, depending on the factory used before/after other SideEffects, while e.g using a ValueChangedListener runs at the same time where the change occurs (and thus might modify state seen by a SideEffects later on). For this specific case I should be able to provide an example if desired, I'm just not sure how/if this could be fixed at all (maybe a BindingContext would be required here instead of SideEffects but its a bit hard to put such restrictions on the consumers of a class to using either of those techniques... So for now it seems that SideEffects do not play well with WidgetProperties/PojoProperties/...
(In reply to Christoph Laeubrich from comment #5) Ah, you're right, I understand what you mean. When jobs are posted async and goes into a work queue in an undefined order it becomes really hard to predict exactly what is going to happen. Should we close this ticket? Since the problem is probably a tricky and weird interaction between SideEffect and async operations. It is not really a bug, and there is no concrete fix.
(In reply to Jens Lideström from comment #6) > Should we close this ticket? Since the problem is probably a tricky and > weird interaction between SideEffect and async operations. It is not really > a bug, and there is no concrete fix. From users perspective this is clearly a bug if the framework behaves unpredictable.
Just out of curiosity, Christoph, it would be interesting to know a little about how you're using the framework! Do you rely on the SideEffect system a lot? Do you use it instead of DataBindingContext? I get that impression because you also commented about SideEffect on bug 565160.
(In reply to Jens Lideström from comment #8) > Just out of curiosity, Christoph, it would be interesting to know a little > about how you're using the framework! > > Do you rely on the SideEffect system a lot? Do you use it instead of > DataBindingContext? > > I get that impression because you also commented about SideEffect on bug > 565160. I almost always use SideEffect and never DataBindingContext as it become quite cumbersome to setup everything manually. Also SideEffect has the advantage that I don't need to expose IObservable in the API but they are still recognized... That way I can simply do factory.create(()-> { //access some generic object to update the UI state }); so if the objects internally use IObvervables they got tracked and updated, if not then there are just no automatic updates. I also wrote some helper methods to access data in way so it is possible for implementations to be called from whatever thread, and some that work around several limitations (e.g. clearing a list that is already empty or replacing just changed values in a remove/addAll call). This allows to have a very flexible and automatic updating UI without much boilerplate code.
(In reply to Christoph Laeubrich from comment #9) > I almost always use SideEffect and never DataBindingContext Interesting approach! Do you have any public code with this pattern that I could look at?
(In reply to Jens Lideström from comment #10) > (In reply to Christoph Laeubrich from comment #9) > > I almost always use SideEffect and never DataBindingContext > > Interesting approach! > > Do you have any public code with this pattern that I could look at? The code is not in a public repository, is there anything you are particularly interested in? I might be able to still share some of the codes or give some insights, feel free to contact me directly via mail if you like or I can also post some examples here if its of broader interest.