Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are listener lists Lists?

Why are listener lists (e.g. in Java those that use addXxxListener() and removeXxxListener() to register and unregister listeners) called lists, and usually implemented as Lists? Wouldn't a Set be a better fit, since in the case of listeners there's

  • No matter in which order they get called (although there may well be such needs, but they're special cases; ordinary listener mechanisms make no such guarantees), and
  • No need to register the same listener more than once (whether doing that should result in calling the same listener 1 times or N times, or be an error, is another question)

Is it just a matter of tradition? Sets are some kind of lists under the hood anyway. Are there performance differences? Is iterating through a List faster or slower than iterating through a Set? Does either take more or less memory? The differences are certainly almost negligible.

like image 538
Joonas Pulakka Avatar asked May 30 '10 10:05

Joonas Pulakka


3 Answers

You are totally right. Listeners should be added to sets. As you said, adding a listener more than once makes no sense. Furthermore one will not rely on the order of the listeners if you use sets. And thats the most important thing: One SHOULD NOT rely on it if you take software development serious and every single principle we found out to lead us to better design: Isolation, Independency, Responsibility.

Every aspect mentioned here (multi threading, performance, ...) has to subordinate itself in the first thought, but may be broken after if you have good reasons. And I mean VERY good reasons.

By the way: It's a bad practise to let the listener remove itself. Adding and removing should be symmetrical. So the listener should be removed through the object that registered it. If you have a lot of listeners involved you will get stuck soon.

like image 178
oopexpert Avatar answered Nov 15 '22 10:11

oopexpert


One important reason for listener lists to be lists (instead of sets) also explains why you often see them being iterated through backwards. A common scenario involves a listener removing itself as a listener when it's notified of some change. If the listeners were stored as a list and iterated forward (or stored as a set and iterated in some undetermined order), removing itself as a listener will cause a ConcurrentModificationException.

So, instead, the listeners are stored as a list and notified in backwards order. Then, if a listener removes itself from the list of listeners when it is notified, it does not cause a ConcurrentModificationException or shift the indices of the other not-yet-notified listeners.

like image 23
Mark Avatar answered Nov 15 '22 10:11

Mark


What kind of set? Should all listeners implement equals and hashCode so that a hash set is used, or would an identity hash set do? Is the use case of adding a listener to a list twice worth the complexity? Is there as simple a mechanism for making the set safe against adding or removing listeners during calls to their handlers?

There might be some performance differences, but there certainly are more complicated design, and it forces the multiple add-multiple remove decision into the library rather than leaving it to the application.

like image 1
Pete Kirkham Avatar answered Nov 15 '22 11:11

Pete Kirkham