Strange behaviour in Spec

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Strange behaviour in Spec

Andrei Chis
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?


Andrei
 

Reply | Threaded
Open this post in threaded view
|

Re: Strange behaviour in Spec

Goubier Thierry
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

Reply | Threaded
Open this post in threaded view
|

Re: Strange behaviour in Spec

Andrei Chis
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 <[hidden email]> 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


Reply | Threaded
Open this post in threaded view
|

Re: Strange behaviour in Spec

Goubier Thierry
Hi Andrei,

I tested with the following code which shows some interesting effects:

|list|
list := ListComposableModel new.
list whenListChanged: [:aList|
Transcript crShow: aList = list listItems].
10 timesRepeat: [
        list items: #(1 2).
        list listItems. "Call listItems to set the cache"
        list items: #(1 2 3).
        list listItems].

And I either get true-true-true-true or, true-false-false-false ...

When I get true-true-true, in list listHolder announcer registry
subscriptions, I have the action
        [:aList| Transcript crShow: aList = list listItems]
set after the action
        [self refreshListItems].

When I get true-false-false-false ad nauseam, in list listHolder
announcer registry subscriptions, I have the action
        [:aList| Transcript crShow: aList = list listItems]
set "before" the action
        [self refreshListItems].

So, it seems that the use of an identitySet in subscriptions for an
announcer has interesting side effects.

So, what should be done ?

1- Change subscription in Announcer SubscriptionRegistry from
IdentitySet to OrderedCollection : it should keep the same behavior in
all users of Announcers, since they have to be order independent
(otherwise, they would fall for the same intermittent bug given the chance).

2- Change ListComposableModel to use a private event to update the cache
before entertaining a #changedValue event.

I have a preference for 1-, because of my soft spot for programs that
have a nice, predictable behavior :)

I've added a ticket

http://code.google.com/p/pharo/issues/detail?id=7420

Thierry

Le 05/02/2013 11:31, Andrei Vasile Chis a écrit :

> 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 <[hidden email]
> <mailto:[hidden email]>> 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
>
>


--
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

Reply | Threaded
Open this post in threaded view
|

Re: Strange behaviour in Spec

Andrei Chis

Hi Thierry,

Thanks for looking into this.
I have a slight preference for solution 2, just because code will not depend on the order of the announcements.

Cheers,
Andrei


On Tue, Feb 5, 2013 at 1:27 PM, Goubier Thierry <[hidden email]> wrote:
Hi Andrei,

I tested with the following code which shows some interesting effects:


|list|  
list := ListComposableModel new.
list whenListChanged: [:aList|
Transcript crShow: aList = list listItems].
10 timesRepeat: [
        list items: #(1 2).

        list listItems. "Call listItems to set the cache"
        list items: #(1 2 3).
        list listItems].

And I either get true-true-true-true or, true-false-false-false ...

When I get true-true-true, in list listHolder announcer registry subscriptions, I have the action

        [:aList| Transcript crShow: aList = list listItems]
set after the action
        [self refreshListItems].

When I get true-false-false-false ad nauseam, in list listHolder announcer registry subscriptions, I have the action

        [:aList| Transcript crShow: aList = list listItems]
set "before" the action
        [self refreshListItems].

So, it seems that the use of an identitySet in subscriptions for an announcer has interesting side effects.

So, what should be done ?

1- Change subscription in Announcer SubscriptionRegistry from IdentitySet to OrderedCollection : it should keep the same behavior in all users of Announcers, since they have to be order independent (otherwise, they would fall for the same intermittent bug given the chance).

2- Change ListComposableModel to use a private event to update the cache before entertaining a #changedValue event.

I have a preference for 1-, because of my soft spot for programs that have a nice, predictable behavior :)

I've added a ticket

http://code.google.com/p/pharo/issues/detail?id=7420

Thierry

Le 05/02/2013 11:31, Andrei Vasile Chis a écrit :
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 <[hidden email]
<mailto:[hidden email]>> 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




--
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


Reply | Threaded
Open this post in threaded view
|

Re: Strange behaviour in Spec

Goubier Thierry
Le 05/02/2013 14:51, Andrei Vasile Chis a écrit :
>
> Hi Thierry,
>
> Thanks for looking into this.
> I have a slight preference for solution 2, just because code will not
> depend on the order of the announcements.

Well, you're lucky. My image crashed while I was trying to prepare the
slice for 1- :(

So I may as well try to do 2- Maybe I'll have more luck.

Thierry

> Cheers,
> Andrei
>
>
> On Tue, Feb 5, 2013 at 1:27 PM, Goubier Thierry <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>     Hi Andrei,
>
>     I tested with the following code which shows some interesting effects:
>
>
>     |list|
>     list := ListComposableModel new.
>     list whenListChanged: [:aList|
>     Transcript crShow: aList = list listItems].
>     10 timesRepeat: [
>              list items: #(1 2).
>
>              list listItems. "Call listItems to set the cache"
>              list items: #(1 2 3).
>              list listItems].
>
>     And I either get true-true-true-true or, true-false-false-false ...
>
>     When I get true-true-true, in list listHolder announcer registry
>     subscriptions, I have the action
>
>              [:aList| Transcript crShow: aList = list listItems]
>     set after the action
>              [self refreshListItems].
>
>     When I get true-false-false-false ad nauseam, in list listHolder
>     announcer registry subscriptions, I have the action
>
>              [:aList| Transcript crShow: aList = list listItems]
>     set "before" the action
>              [self refreshListItems].
>
>     So, it seems that the use of an identitySet in subscriptions for an
>     announcer has interesting side effects.
>
>     So, what should be done ?
>
>     1- Change subscription in Announcer SubscriptionRegistry from
>     IdentitySet to OrderedCollection : it should keep the same behavior
>     in all users of Announcers, since they have to be order independent
>     (otherwise, they would fall for the same intermittent bug given the
>     chance).
>
>     2- Change ListComposableModel to use a private event to update the
>     cache before entertaining a #changedValue event.
>
>     I have a preference for 1-, because of my soft spot for programs
>     that have a nice, predictable behavior :)
>
>     I've added a ticket
>
>     http://code.google.com/p/__pharo/issues/detail?id=7420
>     <http://code.google.com/p/pharo/issues/detail?id=7420>
>
>     Thierry
>
>     Le 05/02/2013 11:31, Andrei Vasile Chis a écrit :
>
>         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
>         <[hidden email] <mailto:[hidden email]>
>         <mailto:[hidden email]
>         <mailto:[hidden email]>__>> 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
>
>
>
>
>     --
>     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
>
>


--
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

Reply | Threaded
Open this post in threaded view
|

Re: Strange behaviour in Spec

Stéphane Ducasse
we can also discuss that friday at the sprint.

Stef

On Feb 5, 2013, at 3:02 PM, Goubier Thierry wrote:

> Le 05/02/2013 14:51, Andrei Vasile Chis a écrit :
>>
>> Hi Thierry,
>>
>> Thanks for looking into this.
>> I have a slight preference for solution 2, just because code will not
>> depend on the order of the announcements.
>
> Well, you're lucky. My image crashed while I was trying to prepare the slice for 1- :(
>
> So I may as well try to do 2- Maybe I'll have more luck.
>
> Thierry
>
>> Cheers,
>> Andrei
>>
>>
>> On Tue, Feb 5, 2013 at 1:27 PM, Goubier Thierry <[hidden email]
>> <mailto:[hidden email]>> wrote:
>>
>>    Hi Andrei,
>>
>>    I tested with the following code which shows some interesting effects:
>>
>>
>>    |list|
>>    list := ListComposableModel new.
>>    list whenListChanged: [:aList|
>>    Transcript crShow: aList = list listItems].
>>    10 timesRepeat: [
>>             list items: #(1 2).
>>
>>             list listItems. "Call listItems to set the cache"
>>             list items: #(1 2 3).
>>             list listItems].
>>
>>    And I either get true-true-true-true or, true-false-false-false ...
>>
>>    When I get true-true-true, in list listHolder announcer registry
>>    subscriptions, I have the action
>>
>>             [:aList| Transcript crShow: aList = list listItems]
>>    set after the action
>>             [self refreshListItems].
>>
>>    When I get true-false-false-false ad nauseam, in list listHolder
>>    announcer registry subscriptions, I have the action
>>
>>             [:aList| Transcript crShow: aList = list listItems]
>>    set "before" the action
>>             [self refreshListItems].
>>
>>    So, it seems that the use of an identitySet in subscriptions for an
>>    announcer has interesting side effects.
>>
>>    So, what should be done ?
>>
>>    1- Change subscription in Announcer SubscriptionRegistry from
>>    IdentitySet to OrderedCollection : it should keep the same behavior
>>    in all users of Announcers, since they have to be order independent
>>    (otherwise, they would fall for the same intermittent bug given the
>>    chance).
>>
>>    2- Change ListComposableModel to use a private event to update the
>>    cache before entertaining a #changedValue event.
>>
>>    I have a preference for 1-, because of my soft spot for programs
>>    that have a nice, predictable behavior :)
>>
>>    I've added a ticket
>>
>>    http://code.google.com/p/__pharo/issues/detail?id=7420
>>    <http://code.google.com/p/pharo/issues/detail?id=7420>
>>
>>    Thierry
>>
>>    Le 05/02/2013 11:31, Andrei Vasile Chis a écrit :
>>
>>        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
>>        <[hidden email] <mailto:[hidden email]>
>>        <mailto:[hidden email]
>>        <mailto:[hidden email]>__>> 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
>>
>>
>>
>>
>>    --
>>    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
>>
>>
>
>
> --
> 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
>