I like your idea of generalizing this solution to enable weak
callbacks in general, but am unable to think of a satisfactory way to
do that.  In pricipal it is easy, but the limitations of C++ would
require writting redirection functions for every function in the
interface.  I can't think of a clean way to to that automaticly.

Let me brainstorm here for a bit.  None of the following ideas
actually work (well some would work but are probably distatefull), but
maybe they will stimulate an idea in someone.

Idea 1:
Add some wrapper layer to C++ that would allow the following:
template<typename T>
class csWeakCallback : T
{
  T *imp;
public:
  csWeakCallback (T *imp) : imp(imp) { }
<%for $func in functions_of(T)%>
  $func () { imp->$func(); }
<%end for%>
};

Idea 1.5:
The same as Idea 1, but use the preprocessor to do that.  (Still
probably not possible b/c the preprocessor would need to be able to
figure out what functions a particular interface had.)

Idea 2:
Find some way to take a pointer to a call back interface (e.g.
iEventHandler*) and produce another pointer to that interface with the
same vtable except for the entries for IncRef and DecRef which would
get assigned to no-op functions.

Idea 3:
Establish some way to "poison" the csRefs that are used internally by
what ever the callback is registered with.

Idea 3a: Establish some kind of weak-object system so csRef could tell
that the pointer it is holding is to an object that should always be
held only weakly.

Idea 3b: Make a "poisoned" csRef that would poison any csRef that it
gets assigned to (poisioned = hold the object only weakly).  Then when
registering the callback use a csRef instead of a pointer which we
will pre-poison.

On 8/4/06, Jorrit Tyberghein <[EMAIL PROTECTED]> wrote:
> I just considered something. I think this solution is focusing too
> much on event handlers but event handlers are not the only type of
> callback where this problem occurs. I can't give examples right now
> but I'm sure there are many other types of callbacks where similar
> problem occurs right now which is also solved with embedding
> interface. So perhaps we should find a way to generalize this so that
> it can work for a general callback type system?
> Perhaps using a template?
>
> Greetings,
>
> On 8/3/06, Michael D. Adams <[EMAIL PROTECTED]> wrote:
> > On 7/29/06, Jorrit Tyberghein <[EMAIL PROTECTED]> wrote:
> > > >   *token = new csWeakEventHandler(listener);
> > >
> > > This is invalid code. You can't use a weak ref like that. Keep in mind
> > > that if the only thing that holds a reference to something is a weak
> > > reference then the object will be removed. You'll have to rework the
> > > code a bit so that after allocation you have a real reference for a
> > > while and then you release that reference as soon as you register to
> > > the event registry.
> > >
> > > I do understand the basic idea of your solution though and it seems
> > > like a possibility.
> >
> > Below is a redraft of the code.  I changed two things.  But I'm not
> > sure whether I am using csHandlerID correctly for the second change.
> >
> > First, I fixed my use of csRef as Jorrit noted should be done.
> >
> > The second change is to make the csWeakEventListener completely
> > invisible to the client code.  Now the csHandlerID that is handed back
> > (by RegisterListener via RegisterWeakListener) is used to lookup the
> > iEventHandler (really a csWeakEventListener) that should be passed on
> > to RemoveListener by RemoveWeakListener.  (As a side benefit, this
> > eliminates the need for an output parameter in RemoveWeakListener to
> > hand back the "csRef<csWeakEventListener>*".)
> >
> > As far as I can tell, there are two kinds of csHandlerID, generic and
> > instance.  The csHandlerID returned by RegisterListener is an instance
> > csHandlerID.  What I'm not 100% sure on is that "instance" in this
> > context means "per object instance".  If it doesn't, then this code
> > probably wont work and I should go back to handing back a
> > "csRef<csWeakEventListener>*".  So can anyone confirm that
> > understanding of "instance csHandlerID"?
> >
> > Michael D. Adams
> > [EMAIL PROTECTED]
> >
> > // The indirection class.  Hidden from client code
> > class csWeakEventHandler :
> >   scfImplementation1<csWeakEventHandler, iEventHandler>
> > {
> > private:
> >   csWeakRef<iEventHandler> parent;
> > public:
> >   csWeakEventHandler (iEventHandler *parent) :
> >     scfImplementationType (this), parent(parent) { }
> >   bool HandleEvent (iEvent& e) { parent->HandleEvent(e); }
> >   /* Similar code to HandleEvent for all the other methods of iEventHandler 
> > */
> > };
> >
> > // Helper function used by client code
> > // May be unnecessary.  The client code can just call the code on its own.
> > csHandlerID RegisterWeakListener (iEventQueue *q, iEventHandler * listener)
> > {
> >   csRef<csWeakEventHandler> handler;
> >   handler.AttachNew (new csWeakEventHandler (listener));
> >   return q->RegisterListener (handler);
> > }
> >
> > // Helper function used by client code.
> > // May be unnecessary.  The client code can just call the code on its own.
> > void RemoveWeakListener (iEventQueue *q, iObjectRegistry *r, csHandlerId id)
> > {
> >   q->RemoveListener(csEventHandlerRegistry::Handler(r, id));
> > }
> >
> > // Example client code
> > class csFoo : scfImplementation2<csFoo, iComponent, iEventHandler>
> > {
> > private:
> >   csHandlerID id;
> > public:
> >   csFoo() : id(CS_HANDLER_INVALID) { /* ... */ }
> >   ~csFoo();
> >   bool Initialize (iObjectRegistry *object_reg);
> >   bool HandleEvent (iEvent& e) { /* ... */ }
> > };
> >
> > bool csFoo::Initialize (iObjectRegistry *object_reg)
> > {
> >   /* ... */
> >   csRef<iEventQueue> q (CS_QUERY_REGISTRY (object_reg, iEventQueue));
> >   if (q != 0)
> >   {
> >     id = RegisterWeakListener(q, this);
> >   }
> >   /* ... */
> >   return true;
> > }
> >
> > csFoo::~csFoo ()
> > {
> >   /* ... */
> >   if (id != CS_HANDLER_INVALID)
> >   {
> >     RemoveWeakListener(q, object_reg, id);
> >   }
> >   /* ... */
> > }

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Crystal-main mailing list
Crystal-main@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/crystal-main
Unsubscribe: mailto:[EMAIL PROTECTED]

Reply via email to