digitalmars.D.announce - Another event handling module
↑ ↓ ← → "John C" <johnch_atms hotmail.com> writes:
A few classes for multicast event handling have been previously released,
and here's another. I think this one's unique in that it allows you to use
both delegates and function pointers (although I may be wrong).
Read more or download it here:
http://www.paperocean.org/cirrus.core.events.html
If you find any bugs, please let me know.
BTW: I've added various ways of chaining together delegates/function
(opAddAssign/opSubAssign, opCatAssign, add/remove method calls). This way
you can use the one you prefer.
John.
↑ ↓ ← → Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
John C wrote:
A few classes for multicast event handling have been previously released,
and here's another. I think this one's unique in that it allows you to use
both delegates and function pointers (although I may be wrong).
dcouple at dsource has them too :-)
What do you do when a recipient gets deleted?
Bastiaan.
↑ ↓ ← → "John C" <johnch_atms hotmail.com> writes:
"Bastiaan Veelo" <Bastiaan.N.Veelo ntnu.no> wrote in message
news:dg1e0u$2ihm$1 digitaldaemon.com...
John C wrote:
A few classes for multicast event handling have been previously released,
and here's another. I think this one's unique in that it allows you to
use both delegates and function pointers (although I may be wrong).
dcouple at dsource has them too :-)
What do you do when a recipient gets deleted?
Good question ... my test program crashes and there doesn't appear to be a
way to check if the delegate still exists - testing for null doesn't work.
Also, I was unable to catch any exceptions. Ideas?
As a workaround, you can call 'remove' to break the connection in the
receiver's destructor. But I'm not sure how this can be done when a function
literal is attached, though.
I've noticed that Ben Hinkle's MultiDelegate exhibits the same problem. I've
not tested dcouple.
Shouldn't the compiler null out delegates that reference nonexistent
methods?
↑ ↓ ← → Sean Kelly <sean f4.ca> writes:
In article <dg1r4v$2tcj$1 digitaldaemon.com>, John C says...
"Bastiaan Veelo" <Bastiaan.N.Veelo ntnu.no> wrote in message
news:dg1e0u$2ihm$1 digitaldaemon.com...
John C wrote:
A few classes for multicast event handling have been previously released,
and here's another. I think this one's unique in that it allows you to
use both delegates and function pointers (although I may be wrong).
dcouple at dsource has them too :-)
What do you do when a recipient gets deleted?
Good question ... my test program crashes and there doesn't appear to be a
way to check if the delegate still exists - testing for null doesn't work.
Also, I was unable to catch any exceptions. Ideas?
I'm not sure if this applies directly, but I use proxy classes for this purpose
in C++. The basic idea is something like this:
# class Proxy(Dest) {
# this() {}
# this( Dest d ) { attach( d ); }
# void attach( Dest d ) { m_dest = d; }
# void detach() { m_dest = null; }
# void opCall() { if( m_dest ) m_dest(); }
# private Dest m_dest;
# }
#
# class C {
# ~this() {
# foreach( Proxy!(C) p; m_proxies )
# p.detach();
# }
# void doSomething() {
# Proxy!(C) p = new Proxy!(C)( this );
# // pass proxy to callback
# m_proxies ~= p;
# }
# private Proxy!(C)[] m_proxies;
# }
As a workaround, you can call 'remove' to break the connection in the
receiver's destructor.
Sounds like you're doing something like the above.
But I'm not sure how this can be done when a function
literal is attached, though.
A delegate you mean? There's not much you can do aside from perhaps putting the
call in a try{}catch(Object){} block, as I think this will trap the access
violation if the referenced object has been destroyed.
I've noticed that Ben Hinkle's MultiDelegate exhibits the same problem. I've
not tested dcouple.
Shouldn't the compiler null out delegates that reference nonexistent
methods?
If so then it may as well do the same for references to objects that have been
cleaned up. I think the issue is that this is simply too expensive to be
worthwhile in most cases.
Sean
↑ ↓ ← → "Ben Hinkle" <bhinkle mathworks.com> writes:
"John C" <johnch_atms hotmail.com> wrote in message
news:dg1r4v$2tcj$1 digitaldaemon.com...
"Bastiaan Veelo" <Bastiaan.N.Veelo ntnu.no> wrote in message
news:dg1e0u$2ihm$1 digitaldaemon.com...
John C wrote:
A few classes for multicast event handling have been previously
released, and here's another. I think this one's unique in that it
allows you to use both delegates and function pointers (although I may
be wrong).
dcouple at dsource has them too :-)
What do you do when a recipient gets deleted?
Good question ... my test program crashes and there doesn't appear to be a
way to check if the delegate still exists - testing for null doesn't work.
Also, I was unable to catch any exceptions. Ideas?
As a workaround, you can call 'remove' to break the connection in the
receiver's destructor. But I'm not sure how this can be done when a
function literal is attached, though.
I've noticed that Ben Hinkle's MultiDelegate exhibits the same problem.
I've not tested dcouple.
Correct. When a programmer deletes an object by hand it is a promise that no
other live references exist. Violating that promise results in crashes.
Shouldn't the compiler null out delegates that reference nonexistent
methods?
↑ ↓ ← → "John C" <johnch_atms hotmail.com> writes:
"Ben Hinkle" <bhinkle mathworks.com> wrote in message
news:dg24mg$2r4$1 digitaldaemon.com...
"John C" <johnch_atms hotmail.com> wrote in message
news:dg1r4v$2tcj$1 digitaldaemon.com...
"Bastiaan Veelo" <Bastiaan.N.Veelo ntnu.no> wrote in message
news:dg1e0u$2ihm$1 digitaldaemon.com...
John C wrote:
A few classes for multicast event handling have been previously
released, and here's another. I think this one's unique in that it
allows you to use both delegates and function pointers (although I may
be wrong).
dcouple at dsource has them too :-)
What do you do when a recipient gets deleted?
Good question ... my test program crashes and there doesn't appear to be
a way to check if the delegate still exists - testing for null doesn't
work. Also, I was unable to catch any exceptions. Ideas?
As a workaround, you can call 'remove' to break the connection in the
receiver's destructor. But I'm not sure how this can be done when a
function literal is attached, though.
I've noticed that Ben Hinkle's MultiDelegate exhibits the same problem.
I've not tested dcouple.
Correct. When a programmer deletes an object by hand it is a promise that
no other live references exist. Violating that promise results in crashes.
Sounds like a fair rule. After all, if you're explictly calling delete
you'll probably want to ensure everything else is cleaned up too.
Shouldn't the compiler null out delegates that reference nonexistent
methods?
↑ ↓ ← → Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
John C wrote:
What do you do when a recipient gets deleted?
Good question ... my test program crashes and there doesn't appear to be a
way to check if the delegate still exists - testing for null doesn't work.
Also, I was unable to catch any exceptions. Ideas?
As a workaround, you can call 'remove' to break the connection in the
receiver's destructor. But I'm not sure how this can be done when a function
literal is attached, though.
I've noticed that Ben Hinkle's MultiDelegate exhibits the same problem. I've
not tested dcouple.
Dcouple solves this with Slot objects and managing code. I am ioning out
some segfaults in version 0.3, but 0.2 should work.
Shouldn't the compiler null out delegates that reference nonexistent
methods?
That would be nice, but how would the compiler know? There is a concept
called weak references, that has been brought up a couple of times in
this context. See the post "Resources" on the dcouple forum at dsource.
Bastiaan.
↑ ↓ ← → Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
Bastiaan Veelo wrote:
Dcouple solves this with Slot objects and managing code.
Version 0.3 (currently in the svn trunk) works per today
(http://svn.dsource.org/projects/dcouple/trunk/managed/dcouple/). The
dcouple version of Ben's example from multidg.d is given below
#import dcouple.connect;
#import dcouple.release;
#import dcouple.signalslot;
#
#class Foo : SignalSlotManager
#{
# mixin SignalSlotManagement;
#
# Signal!(int) valueChanged;
# Slot!(int) changeValue;
#
# private int val;
#
# this()
# {
# valueChanged = new Signal!(int)(this);
# changeValue = new Slot!(int)(this, &value);
# }
#
# ~this()
# {
# deleteSignals();
# deleteSlots();
# }
#
# int value()
# {
# return val;
# }
#
# void value(int v)
# {
# if (val != v) {
# val = v;
# valueChanged.emit(v);
# }
# }
#}
#
#import std.stdio;
#int main() {
# writefln("Compiled with ", dcoupleVersion() );
# Foo a = new Foo;
# Foo b = new Foo;
# connect(a.valueChanged, b.changeValue);
# writefln(a.value," ",b.value);
# b.value = 11;
# writefln(a.value," ",b.value);
# a.value = 79;
# writefln(a.value," ",b.value);
# delete b; // Note delete!
# a.value = 100;
# writefln(a.value);
# return 0;
#}
(also available here
http://svn.dsource.org/projects/dcouple/trunk/managed/examples/delete_example.d)
output is
Compiled with dcouple version 0.3, copyright 2004, 2005 Bastiaan Veelo.
0 0
0 11
79 79
100
So dcouple lets you tie together objects, and handle them any way you
like regardless what ties exist. If you delete an object, existing ties
clean themselves up.
Bastiaan.
↑ ↓ ← → "Ben Hinkle" <bhinkle mathworks.com> writes:
# ~this()
# {
# deleteSignals();
# deleteSlots();
# }
Does deleteSignals and deleteSlots reference other GC-managed objects or
arrays? If so then you'll get random seg-v's during a GC. Objects are
collected in random order and so the other objects might be gone by the time
~this runs. The details (as they are) are in
http://www.digitalmars.com/d/class.html#destructors
↑ ↓ ← → Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
Ben Hinkle wrote:
# ~this()
# {
# deleteSignals();
# deleteSlots();
# }
Does deleteSignals and deleteSlots reference other GC-managed objects or
arrays?
Yes, but only to objects (Signals and Slots) that know about each other
and about their managers (the ones calling deleteSignals and/or
deleteSlots). In their destructor they deregister themselves with these
referencing objects. So at the time of destruction, only references
exist to objects that have not been destructed yet. Therefore, the order
of destruction does not matter.
Bastiaan.
↑ ↓ ← → "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Bastiaan Veelo" <Bastiaan.N.Veelo ntnu.no> wrote in message
news:dg8nsc$f9l$1 digitaldaemon.com...
Ben Hinkle wrote:
# ~this()
# {
# deleteSignals();
# deleteSlots();
# }
Does deleteSignals and deleteSlots reference other GC-managed objects or
arrays?
Yes, but only to objects (Signals and Slots) that know about each other
and about their managers (the ones calling deleteSignals and/or
deleteSlots). In their destructor they deregister themselves with these
referencing objects. So at the time of destruction, only references exist
to objects that have not been destructed yet. Therefore, the order of
destruction does not matter.
Ok, though note the dynamic array used to store the data is also GC-managed
and has no destructor.
Bastiaan.
↑ ↓ ← → Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
Ben Hinkle wrote:
Ok, though note the dynamic array used to store the data is also GC-managed
and has no destructor.
Hm. Thanks for pointing that out. I have not been bitten by that fact
yet, could it be that objects do get collected before arrays in the
current implementation of the garbage collector?
What do you think would be the best defence, a linked list using malloc
and free?
Dcouple is kind of a study for me, I am not sure yet whether it is
better/nicer to explicitly delete an object or to disconnect all its
connections (e.g. by means of a "discard" method) and let the GC take
care of it. I am mainly thinking GUI programming here.
↑ ↓ ← → =?utf-8?B?RGF3aWQgQ2nEmcW8YXJraWV3aWN6?= <araelx gmail.com> writes:
On Thu, 15 Sep 2005 17:12:06 +0200, Bastiaan Veelo
<Bastiaan.N.Veelo ntnu.no> wrote:
Dcouple is kind of a study for me, I am not sure yet whether it is
better/nicer to explicitly delete an object or to disconnect all its
connections (e.g. by means of a "discard" method) and let the GC take
care of it. I am mainly thinking GUI programming here.
Very good question. I often consider this problem by myself. "Dereference
and forget" vs. "explicity delete". Any thoughts about this matter, anyone?
--
Dawid Ciężarkiewicz
↑ ↓ ← → "Ben Hinkle" <bhinkle mathworks.com> writes:
"Bastiaan Veelo" <Bastiaan.N.Veelo ntnu.no> wrote in message
news:dg8nsc$f9l$1 digitaldaemon.com...
Ben Hinkle wrote:
# ~this()
# {
# deleteSignals();
# deleteSlots();
# }
Does deleteSignals and deleteSlots reference other GC-managed objects or
arrays?
Yes, but only to objects (Signals and Slots) that know about each other
and about their managers (the ones calling deleteSignals and/or
deleteSlots). In their destructor they deregister themselves with these
referencing objects. So at the time of destruction, only references exist
to objects that have not been destructed yet. Therefore, the order of
destruction does not matter.
Bastiaan.
I should add that if all the objects have references to one another then if
one of the objects is garbage they are all. So having destructors that
remove the connection is only useful when someone explicitly calls delete on
an object still connected.
↑ ↓ ← → Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
Ben Hinkle wrote:
Yes, but only to objects (Signals and Slots) that know about each other
and about their managers (the ones calling deleteSignals and/or
deleteSlots). In their destructor they deregister themselves with these
referencing objects. So at the time of destruction, only references exist
to objects that have not been destructed yet. Therefore, the order of
destruction does not matter.
Bastiaan.
I should add that if all the objects have references to one another then if
one of the objects is garbage they are all. So having destructors that
remove the connection is only useful when someone explicitly calls delete on
an object still connected.
Yes. So in this case calling delete Object or Object.discard() is
somewhat equivalent (where discard() is a method that disconnects all
signals and slots of Object). The former is immediate and familiar to
C++ programmers, the latter is delayed and a bit special.
Bastiaan.
↑ ↓ ← → "Uwe Salomon" <post uwesalomon.de> writes:
Indigo also contains a signals&slots implementation. It is partly
malloc-based to avoid GC problems, and very simple to use (without signal
managers and other complexity classes). You can have a look at it at:
http://www.uwesalomon.de/code/indigo/files/core/cmdtarget-d.html#Signals_and_slots
Ciao
uwe
↑ ↓ ← → Bastiaan Veelo <Bastiaan.N.Veelo ntnu.no> writes:
Uwe Salomon wrote:
Indigo also contains a signals&slots implementation. It is partly
malloc-based to avoid GC problems, and very simple to use (without
signal managers and other complexity classes). You can have a look at
it at:
http://www.uwesalomon.de/code/indigo/files/core/cmdtarget-d.ht
l#Signals_and_slots
Ciao
uwe
Nice work. I like the ability to connect partly compatible signals and
slots.
From the documentation:
Connections between objects will not detain the garbage collector from
recycling them if they are not referenced otherwise.
Cool! I will have a closer look.
Bastiaan.
|