[Biojava-l] ChangeSupport, WeakReferences, & docs

Rhett Sutphin rhett-sutphin at uiowa.edu
Fri Mar 21 09:01:21 EST 2003


Hi Matthew,

On Friday, March 21, 2003, at 05:05  AM, Matthew Pocock wrote:
> It's a problem, isn't it. The documentation should
> certainly be added. I'm a little uneasy about
> StrongRefChangeSupport because it's usualy the one
> registering the listener that needs to know if the
> reference is strong or weak, and there would be no way
> for them to discover this from a Changeable (without

I agree about that.  I proposed StrongRefChangeSupport to give 
end-developers the option of using a strong-reference-based solution 
after evaluating the uses and potential costs/benefits for their 
projects.  Since event handling is not BioJava's raison d'etre, it's 
fine with me if StrongRefChangeSupport just stays in the mailing list 
archive for reference (so to speak).

[I also don't think that adding something like 
canUseAnonEventListeners() to Changeable would be of any practical use 
-- the reason that anonymous event handlers are appealing is that they 
are code-light and easy to understand.  If you had to wrap each use in 
a big conditional (and provide an alternative) that appeal goes out the 
window.  The result would be that people just wouldn't use anonymous 
handlers with Changeables.  This result can much more easily be 
accomplished through documentation.]

> adding extra Changeable API which I'm loathed to
> sudgest). Perhaps this needs documenting in big
> flashing lights within Changeable as well.

That's probably a good idea.  In Changeable there could be a message 
describing the potential pitfalls & benefits of using ChangeSupport to 
implement it.  Then in classes that do use it could have some sort of 
boilerplate message that refers to this description.  Ex: "This class' 
implementation of Changeable does not support anonymous event 
listeners.  See Changeable for details."

Rhett

--
Rhett Sutphin
Research Assistant (Software)
Coordinated Laboratory for Computational Genomics
   and the Center for Macular Degeneration
University of Iowa - Iowa City, IA 52242 - USA
4111 MEBRF - email: rhett-sutphin at uiowa.edu



>  --- Rhett Sutphin <rhett-sutphin at uiowa.edu> wrote: >
> Hi,
>>
>> I am using org.biojava.utils.ChangeSupport in a
>> application I'm
>> writing.  I noticed some odd behavior yesterday:
>> some of my
>> ChangeListeners would stop being notified after the
>> program had been
>> executing for a short while.  After some false
>> starts, I looked at the
>> ChangeSupport source and discovered that it only
>> maintains weak
>> references to the ChangeListeners registered in it.
>>
>> After looking through the mailing list archives, I
>> understand why this
>> is desirable in some instances (see
>>
> http://www.biojava.org/pipermail/biojava-l/2000-December/000578.html).
>>
>> Unfortunately, it conflicts with a common
>> java-event-handling idiom:
>> the inner class event handler (anonymous or not).
>> When you do
>> something like this:
>>
>> chgable.addChangeListener(new ChangeAdapter() {
>>      public void postChange(ChangeEvent ce) {
>>          doSomething();
>>      }
>> });
>>
>> or this:
>>
>> chgable.addChangeListener(new InnerChangeHandler());
>>
>> where chgable uses ChangeSupport, it silently stops
>> working shortly
>> after the application starts up because the only
>> reference to the event
>> handler is the weak reference in the ChangeSupport
>> object.
>>
>> Since the WeakReference use is, on one hand, a
>> reasonable solution to a
>> memory-efficiency problem but, on the other hand,
>> silently causes odd
>> behavior in some instances, I propose that this
>> should be documented.
>> Something like this might be sufficient:
>>
>>    ---
>> Warning:  ChangeSupport only maintains weak
>> references to registered
>> ChangeListeners.  This means that any ChangeListener
>> registered to it
>> will stop receiving change events (because it is
>> garbage-collected) as
>> soon as all other references to the ChangeListener
>> go out of scope.
>> Classes that use ChangeSupport are advised to
>> document this, as it will
>> make anonymous event handlers fail to behave as
>> expected.
>>    ---
>>
>> In addition to this, it might be reasonable to add a
>> version of
>> ChangeSupport that uses strong references for those
>> who are aware of
>> the risks and don't care.  A quick-and-dirty version
>> of such a class
>> appears below.
>>
>> Rhett
>>
>> ------ StrongRefChangeSupport.java ------
>>
>> import org.biojava.utils.ChangeSupport;
>> import org.biojava.utils.ChangeListener;
>> import org.biojava.utils.ChangeType;
>>
>> import java.util.Set;
>> import java.util.HashSet;
>>
>> /**
>>   * An implementation of ChangeSupport that
>> maintains strong references
>>   * to registered ChangeListeners.  This makes it
>> suitable for use with
>>   * anonymous ChangeListeners, but introduces the
>> potential for memory
>>   * leaks when a large object listens to a
>> long-lived object.
>>   */
>> public class StrongRefChangeSupport extends
>> ChangeSupport {
>>      private Set strongRefs;
>>
>>      public StrongRefChangeSupport() {
>>          super();
>>          initStrongRefs();
>>      }
>>
>>      public StrongRefChangeSupport(int initialSize)
>> {
>>          super(initialSize);
>>          initStrongRefs();
>>      }
>>
>>      public StrongRefChangeSupport(int initialSize,
>> int delta) {
>>          super(initialSize, delta);
>>          initStrongRefs();
>>      }
>>
>>      public StrongRefChangeSupport(Set unchanging) {
>>          super(unchanging);
>>          initStrongRefs();
>>      }
>>
>>      public StrongRefChangeSupport(Set unchanging,
>> int initialSize, int
>> delta) {
>>          super(unchanging, initialSize, delta);
>>          initStrongRefs();
>>      }
>>
>>      private void initStrongRefs() {
>>          strongRefs = new HashSet();
>>      }
>>
>>      public void addChangeListener(ChangeListener
>> cl, ChangeType ct) {
>>          super.addChangeListener(cl, ct);
>>          strongRefs.add(new Key(cl, ct));
>>      }
>>
>>      public void removeChangeListener(ChangeListener
>> cl, ChangeType ct) {
>>          super.removeChangeListener(cl, ct);
>>          strongRefs.remove(new Key(cl, ct));
>>      }
>>
>>      private static class Key {
>>          private final ChangeListener cl;
>>          private final ChangeType ct;
>>          public Key(ChangeListener cl, ChangeType
>> ct) {
>>              this.cl = cl;
>>              this.ct = ct;
>>          }
>>
>>          public boolean equals(Object other) {
>>              if (!(other instanceof Key)) return
>> false;
>>              Key oKey = (Key) other;
>>              return (oKey.cl == this.cl && oKey.ct
>> == this.ct);
>>          }
>>
>>          public int hashCode() {
>>              return cl.hashCode() + ct.hashCode();
>>          }
>>      }
>> }
>>
>> ------ StrongRefChangeSupport.java ------
>>



More information about the Biojava-l mailing list