Hi, A very simple way to reproduce is to open a transcript and execute this code: 50 timesRepeat: [|list| list := ListComposableModel new. list items: #(1 2). list whenListChanged: [:aList| Transcript crShow: aList = list listItems]. list listItems. "Call listItems to set the cache" list items: #(1 2 3) ]. If should print both true and false. Every time it prins false the events were triggered in the wrong order. Andrei On Tue, Feb 5, 2013 at 9:26 AM, Goubier Thierry <thierry.goubier@cea.fr>wrote:
Le 04/02/2013 17:27, Andrei Vasile Chis a écrit :
Hi,
While playing with spec I started to have some quite random and strange behaviour. I'll try to explain what happen, because it might be a nasty/not that nasty bug.
I had a ListComposableModel and some very simple code like: aListComposableModel whenListChanged: [ :aList | aListComposableModel setSelectedItem: aList first ].
From time to time this code seem to randomly fail because the selection wasn't set. I manage to reduce the error to the following equivalent code: aListComposableModel whenListChanged: [ :aList | aList = aListComposableModel listItems ].
What happen was that sometimes the list held by the model was the previous list and not the new list, which was actually correctly passes to the block.
This seem to be caused by the way ListComposableModel uses announcers to update its internal state. In ListComposableModel>>**registerEvents there is the code: listHolder whenChangedDo: [ self refreshListItems ].
This registers an announcement that should clear the cache: ListComposableModel >>refreshListItems listItemsCache := nil. ^ self changed: #listElementAt:
In my code by using 'aListComposableModel whenListChanged:' I also register an event that should be executed when the elements of the list change.
So by now the listHolder containing the elements of the list has two registered events. The problem is that in order for this to work correctly they have to execute in the order they were added: first invalidate the cache, then the other events registered by the user. However I do not think that announcers guarantee this. So from time to time they execute in the wrong way. This means that the code in the whenListChanged: block will execute in a state in which internaly aListComposableModel still contains the previous list.
Does this make sense?
Yes. It would mean the two announcers are kept in a Set... Maybe having private and public events would be the way to go ? A private one for clearing the cache and public ones, triggered after, for the whenListChanged: block ?
It would be nice to have a test case checking that. I'd be interested to know this can happen with announcements.
Thierry -- Thierry Goubier CEA list Laboratoire des Fondations des Systèmes Temps Réel Embarqués 91191 Gif sur Yvette Cedex France Phone/Fax: +33 (0) 1 69 08 32 92 / 83 95