|
Archives
D Programming
D
D.gnu
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger
C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows
digitalmars.empire
digitalmars.DMDScript
|
digitalmars.D - Suggestion: signal/slot mechanism
↑ ↓ ← → Kristian <kjkilpi gmail.com> writes:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It beats
event table declarations used by other GUI libraries IMHO.
It would make D a lot more appealing language to write GUI applications.
Think of wxWidgets written in D... ;)
I think it would be quite simple to build a S/S support for a compiler (at
first glance, at least). For example:
The 'Object' class has a pointer to S/S data (it's null if the object
don't currently use signals/slots). S/S data holds a slot list for each
signal. It also holds a list of objects that have slot(s) connected to
this object's signal(s). This list is used to disconnect necessary slots
at a destruction of the object.
When the compiler reads a 'emit X' statement, it will do two things.
First, it generates an id for the signal which is used to retrieve a
correct slot list.
Second, the compiler puts the signal's parameters to the stack as it would
call a corresponding function. Instead, the 'Object._emit_signal(id)'
function (or something) is called, where 'id' is the generated id. (Note
that there are no function bodies for signals.) '_emit_signal()' retrieves
the correct slot list, and calls all the slots (delegates) in it. Finally
the parameters are removed from the stack.
Of course, slots should not modify their parameters so that all the slots
will receive the same parameter values. Hence slots should not use the
'out type'. There is a market for a 'const type' here... *wink*
Maybe there should be no slot keyword at all as there is in Qt. You don't
need to declare a function to be a slot; all the (virtual) functions can
be used with signals.
Because the return values of all the signals are void, the void typeword
could be removed from signal declarations.
signal clicked();
signals:
clicked();
clicked(int button);
BTW, Qt generates ids for signals as follows:
signals:
void clicked(int button, bool isMoved);
-> the id is a string "clicked(int,bool)"
↑ ↓ ← → Lutger <lutger.blijdestijn gmail.com> writes:
Kristian wrote:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It beats
event table declarations used by other GUI libraries IMHO.
It would make D a lot more appealing language to write GUI applications.
Think of wxWidgets written in D... ;)
I think it would be quite simple to build a S/S support for a compiler
(at first glance, at least). For example:
The 'Object' class has a pointer to S/S data (it's null if the object
don't currently use signals/slots). S/S data holds a slot list for each
signal. It also holds a list of objects that have slot(s) connected to
this object's signal(s). This list is used to disconnect necessary slots
at a destruction of the object.
When the compiler reads a 'emit X' statement, it will do two things.
First, it generates an id for the signal which is used to retrieve a
correct slot list.
Second, the compiler puts the signal's parameters to the stack as it
would call a corresponding function. Instead, the
'Object._emit_signal(id)' function (or something) is called, where 'id'
is the generated id. (Note that there are no function bodies for
signals.) '_emit_signal()' retrieves the correct slot list, and calls
all the slots (delegates) in it. Finally the parameters are removed from
the stack.
Of course, slots should not modify their parameters so that all the
slots will receive the same parameter values. Hence slots should not use
the 'out type'. There is a market for a 'const type' here... *wink*
Maybe there should be no slot keyword at all as there is in Qt. You
don't need to declare a function to be a slot; all the (virtual)
functions can be used with signals.
Because the return values of all the signals are void, the void typeword
could be removed from signal declarations.
signal clicked();
signals:
clicked();
clicked(int button);
BTW, Qt generates ids for signals as follows:
signals:
void clicked(int button, bool isMoved);
-> the id is a string "clicked(int,bool)"
I agree the signal-slot mechanism is nice, but why must it be supported
by a compiler? There a lots of good libraries in C++ for this, such as
sigslots, libsigc++ and boost::signals. It is not necessary to have
extra preprocessor or language support.
It should be possible to do this in a D library. There already is
dcouple at dsource, but it is inactive. I have been working on a
signal-slot module myself, the only thing missing now is automatic
disconnections of which I am not sure how and if to proceed.
↑ ↓ ← → Kristian <kjkilpi gmail.com> writes:
On Sat, 02 Sep 2006 14:20:22 +0300, Lutger <lutger.blijdestijn gmail.com>
wrote:
Kristian wrote:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It beats
event table declarations used by other GUI libraries IMHO.
It would make D a lot more appealing language to write GUI
applications. Think of wxWidgets written in D... ;)
I agree the signal-slot mechanism is nice, but why must it be supported
by a compiler? There a lots of good libraries in C++ for this, such as
sigslots, libsigc++ and boost::signals. It is not necessary to have
extra preprocessor or language support.
It should be possible to do this in a D library. There already is
dcouple at dsource, but it is inactive. I have been working on a
signal-slot module myself, the only thing missing now is automatic
disconnections of which I am not sure how and if to proceed.
Well, one could ask if it's possible to implement a signal/slot mechanism
by using a library (or by doing it by yourself), then why none of the GUI
libraries I'm familiar with do not use it? (Qt uses preprocessor.)
There are several general reasons for a feature being directly supported:
- If a feature is supported by a language, programmers will use it a lot
more often. Actually it almost certainly guarantees that a feature will be
used.
- Syntax sugar. Being the part of a language, the syntax is consistent
with the rest of the statements. This makes the feature (usually) simplier
and easier to use. At least overall readability is better.
- Compile time errors could be more informative.
- If there is a compiler for a operating system, then the feature is
automatically supported in that system, of course.
- You can rely on the feature being bug free. (You can make that
assumption.)
And of course, the S/S mechanism wouldn't look bad at the feature list of
D. ;)
↑ ↓ ← → Brad Anderson <brad dsource.org> writes:
Kristian wrote:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It beats
event table declarations used by other GUI libraries IMHO.
It would make D a lot more appealing language to write GUI applications.
Think of wxWidgets written in D... ;)
I think it would be quite simple to build a S/S support for a compiler
(at first glance, at least). For example:
The 'Object' class has a pointer to S/S data (it's null if the object
don't currently use signals/slots). S/S data holds a slot list for each
signal. It also holds a list of objects that have slot(s) connected to
this object's signal(s). This list is used to disconnect necessary slots
at a destruction of the object.
When the compiler reads a 'emit X' statement, it will do two things.
First, it generates an id for the signal which is used to retrieve a
correct slot list.
Second, the compiler puts the signal's parameters to the stack as it
would call a corresponding function. Instead, the
'Object._emit_signal(id)' function (or something) is called, where 'id'
is the generated id. (Note that there are no function bodies for
signals.) '_emit_signal()' retrieves the correct slot list, and calls
all the slots (delegates) in it. Finally the parameters are removed from
the stack.
Of course, slots should not modify their parameters so that all the
slots will receive the same parameter values. Hence slots should not use
the 'out type'. There is a market for a 'const type' here... *wink*
Maybe there should be no slot keyword at all as there is in Qt. You
don't need to declare a function to be a slot; all the (virtual)
functions can be used with signals.
Because the return values of all the signals are void, the void typeword
could be removed from signal declarations.
signal clicked();
signals:
clicked();
clicked(int button);
BTW, Qt generates ids for signals as follows:
signals:
void clicked(int button, bool isMoved);
-> the id is a string "clicked(int,bool)"
Not terribly active recently, but the SVN repos here may have some stuff for
you.
http://svn.dsource.org/projects/dcouple/
BA
↑ ↓ ← → Kristian <kjkilpi gmail.com> writes:
On Sun, 03 Sep 2006 01:41:55 +0300, Brad Anderson <brad dsource.org> wrote:
Kristian wrote:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It beats
event table declarations used by other GUI libraries IMHO.
It would make D a lot more appealing language to write GUI applications.
Think of wxWidgets written in D... ;)
I think it would be quite simple to build a S/S support for a compiler
(at first glance, at least). For example:
The 'Object' class has a pointer to S/S data (it's null if the object
don't currently use signals/slots). S/S data holds a slot list for each
signal. It also holds a list of objects that have slot(s) connected to
this object's signal(s). This list is used to disconnect necessary slots
at a destruction of the object.
When the compiler reads a 'emit X' statement, it will do two things.
First, it generates an id for the signal which is used to retrieve a
correct slot list.
Second, the compiler puts the signal's parameters to the stack as it
would call a corresponding function. Instead, the
'Object._emit_signal(id)' function (or something) is called, where 'id'
is the generated id. (Note that there are no function bodies for
signals.) '_emit_signal()' retrieves the correct slot list, and calls
all the slots (delegates) in it. Finally the parameters are removed from
the stack.
Of course, slots should not modify their parameters so that all the
slots will receive the same parameter values. Hence slots should not use
the 'out type'. There is a market for a 'const type' here... *wink*
Maybe there should be no slot keyword at all as there is in Qt. You
don't need to declare a function to be a slot; all the (virtual)
functions can be used with signals.
Because the return values of all the signals are void, the void typeword
could be removed from signal declarations.
signal clicked();
signals:
clicked();
clicked(int button);
BTW, Qt generates ids for signals as follows:
signals:
void clicked(int button, bool isMoved);
-> the id is a string "clicked(int,bool)"
Not terribly active recently, but the SVN repos here may have some stuff
for you.
http://svn.dsource.org/projects/dcouple/
BA
Thanks. I like dcouple's syntax. (There seem to be some problems with GC
and object deletion currently though.) Being a library, you have to create
signal and slot objects in constructors, which is a downside (when
compared against S/S mechanism build into D).
↑ ↓ ← → Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Kristian wrote:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It beats
event table declarations used by other GUI libraries IMHO.
It would make D a lot more appealing language to write GUI applications.
Think of wxWidgets written in D... ;)
I think it would be quite simple to build a S/S support for a compiler
(at first glance, at least). For example:
The 'Object' class has a pointer to S/S data (it's null if the object
don't currently use signals/slots). S/S data holds a slot list for each
signal. It also holds a list of objects that have slot(s) connected to
this object's signal(s). This list is used to disconnect necessary slots
at a destruction of the object.
When the compiler reads a 'emit X' statement, it will do two things.
First, it generates an id for the signal which is used to retrieve a
correct slot list.
Second, the compiler puts the signal's parameters to the stack as it
would call a corresponding function. Instead, the
'Object._emit_signal(id)' function (or something) is called, where 'id'
is the generated id. (Note that there are no function bodies for
signals.) '_emit_signal()' retrieves the correct slot list, and calls
all the slots (delegates) in it. Finally the parameters are removed from
the stack.
Of course, slots should not modify their parameters so that all the
slots will receive the same parameter values. Hence slots should not use
the 'out type'. There is a market for a 'const type' here... *wink*
Maybe there should be no slot keyword at all as there is in Qt. You
don't need to declare a function to be a slot; all the (virtual)
functions can be used with signals.
Because the return values of all the signals are void, the void typeword
could be removed from signal declarations.
signal clicked();
signals:
clicked();
clicked(int button);
BTW, Qt generates ids for signals as follows:
signals:
void clicked(int button, bool isMoved);
-> the id is a string "clicked(int,bool)"
The Signal and slots pattern is little more than an abstraction for
languages that do not support delegates (and dynamic arrays). Which is
not the case for D:
// Declare a signal:
void delegate(Button, int)[] someSignal;
// Connect a slot to a signal:
someSignal ~= foo.someSlot;
// emit the signal
foreach(dg; someSignal)
dg(myButton, myInt);
The only limitation I see with D so far, is on the emit part. You can't
create an emit function that works like this:
emit(someSignal, myButton, myInt);
and that would do the same as that foreach. Because you cannot do
"parameterized"(whether compile time or runtime) function calls.
--
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
↑ ↓ ← → Juan Jose Comellas <jcomellas gmail.com> writes:
Bruno Medeiros wrote:
The Signal and slots pattern is little more than an abstraction for
languages that do not support delegates (and dynamic arrays). Which is
not the case for D:
// Declare a signal:
void delegate(Button, int)[] someSignal;
// Connect a slot to a signal:
someSignal ~= foo.someSlot;
// emit the signal
foreach(dg; someSignal)
dg(myButton, myInt);
The only limitation I see with D so far, is on the emit part. You can't
create an emit function that works like this:
emit(someSignal, myButton, myInt);
and that would do the same as that foreach. Because you cannot do
"parameterized"(whether compile time or runtime) function calls.
This problem is usually solved by creating a template signal class per
number of parameters that it can allow (i.e. the arity of the signal).
You'd have something like:
template Signal0() { ... }
template Signal1(T1) { ... }
template Signal2(T1, T2) { ... }
template Signal3(T1, T2, T3) { ... }
...
This is the solution used by libsigc++, boost, Qt Jambi, etc.
↑ ↓ ← → Kristian <kjkilpi gmail.com> writes:
On Sun, 03 Sep 2006 13:01:28 +0300, Bruno Medeiros =
<brunodomedeiros+spam com.gmail> wrote:
Kristian wrote:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It beat=
event table declarations used by other GUI libraries IMHO.
It would make D a lot more appealing language to write GUI =
applications. Think of wxWidgets written in D... ;)
I think it would be quite simple to build a S/S support for a =
compiler (at first glance, at least). For example:
The 'Object' class has a pointer to S/S data (it's null if the objec=
don't currently use signals/slots). S/S data holds a slot list for ea=
signal. It also holds a list of objects that have slot(s) connected t=
this object's signal(s). This list is used to disconnect necessary =
slots at a destruction of the object.
When the compiler reads a 'emit X' statement, it will do two things.=
First, it generates an id for the signal which is used to retrieve a =
correct slot list.
Second, the compiler puts the signal's parameters to the stack as it=
would call a corresponding function. Instead, the =
'Object._emit_signal(id)' function (or something) is called, where 'i=
is the generated id. (Note that there are no function bodies for =
signals.) '_emit_signal()' retrieves the correct slot list, and calls=
all the slots (delegates) in it. Finally the parameters are removed =
from the stack.
Of course, slots should not modify their parameters so that all the =
slots will receive the same parameter values. Hence slots should not =
use the 'out type'. There is a market for a 'const type' here... *win=
Maybe there should be no slot keyword at all as there is in Qt. You=
don't need to declare a function to be a slot; all the (virtual) =
functions can be used with signals.
Because the return values of all the signals are void, the void =
typeword could be removed from signal declarations.
signal clicked();
signals:
clicked();
clicked(int button);
BTW, Qt generates ids for signals as follows:
signals:
void clicked(int button, bool isMoved);
-> the id is a string "clicked(int,bool)"
The Signal and slots pattern is little more than an abstraction for =
languages that do not support delegates (and dynamic arrays). Which is=
not the case for D:
// Declare a signal:
void delegate(Button, int)[] someSignal;
// Connect a slot to a signal:
someSignal ~=3D foo.someSlot;
// emit the signal
foreach(dg; someSignal)
dg(myButton, myInt);
The only limitation I see with D so far, is on the emit part. You can'=
create an emit function that works like this:
emit(someSignal, myButton, myInt);
and that would do the same as that foreach. Because you cannot do =
"parameterized"(whether compile time or runtime) function calls.
Automatic S/S disconnection at object destructions should also be =
implemented, usually, which requires the use of a base class.
I think everybody will agree if I say that the optimal solution would be=
D =
supporting S/S mechanism directly.
It would make using of signals/slots as easy as calling of functions, fo=
r =
instance. But if Walter (and D community) thinks that the S/S mechanism =
is =
not important enough to be added to D specs (ever), then Phobos should =
have a S/S library (in the future). It would make implementation of =
classes having signals/slots more tedious though. Fortunately using of =
such classes would be as easy (I looked at some examples of dcouple).
↑ ↓ ← → Lutger <lutger.blijdestijn gmail.com> writes:
Kristian wrote:
<snip>
Automatic S/S disconnection at object destructions should also be
implemented, usually, which requires the use of a base class.
I think everybody will agree if I say that the optimal solution would be
D supporting S/S mechanism directly.
It would make using of signals/slots as easy as calling of functions,
for instance. But if Walter (and D community) thinks that the S/S
mechanism is not important enough to be added to D specs (ever), then
Phobos should have a S/S library (in the future). It would make
implementation of classes having signals/slots more tedious though.
Fortunately using of such classes would be as easy (I looked at some
examples of dcouple).
I think there are benefits / downsides to both options of language and
library implementation. Personally I favor a library option, and if it
would be included in some (de facto or official) standard library that
would be good indeed.
In C++ the existing library solutions are very nice and prove that a
preprocessor like QT uses is not needed at all. I think it can be done
in D even better, because of delegate support and template features.
The benefit of a library solution is less language bloat, more flexible
and possible competition. Some libraries also perhaps don't want to
use the signal-slot mechanism, like harmonia which prefers to use
sinking-bubbling.
It's not that it's not important enough, it's more that it fits better
in a library for a language like D imho.
↑ ↓ ← → Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Kristian wrote:
On Sun, 03 Sep 2006 13:01:28 +0300, Bruno Medeiros
<brunodomedeiros+spam com.gmail> wrote:
Kristian wrote:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It
beats event table declarations used by other GUI libraries IMHO.
It would make D a lot more appealing language to write GUI
applications. Think of wxWidgets written in D... ;)
I think it would be quite simple to build a S/S support for a
compiler (at first glance, at least). For example:
The 'Object' class has a pointer to S/S data (it's null if the
object don't currently use signals/slots). S/S data holds a slot list
for each signal. It also holds a list of objects that have slot(s)
connected to this object's signal(s). This list is used to disconnect
necessary slots at a destruction of the object.
When the compiler reads a 'emit X' statement, it will do two things.
First, it generates an id for the signal which is used to retrieve a
correct slot list.
Second, the compiler puts the signal's parameters to the stack as it
would call a corresponding function. Instead, the
'Object._emit_signal(id)' function (or something) is called, where
'id' is the generated id. (Note that there are no function bodies for
signals.) '_emit_signal()' retrieves the correct slot list, and calls
all the slots (delegates) in it. Finally the parameters are removed
from the stack.
Of course, slots should not modify their parameters so that all the
slots will receive the same parameter values. Hence slots should not
use the 'out type'. There is a market for a 'const type' here... *wink*
Maybe there should be no slot keyword at all as there is in Qt. You
don't need to declare a function to be a slot; all the (virtual)
functions can be used with signals.
Because the return values of all the signals are void, the void
typeword could be removed from signal declarations.
signal clicked();
signals:
clicked();
clicked(int button);
BTW, Qt generates ids for signals as follows:
signals:
void clicked(int button, bool isMoved);
-> the id is a string "clicked(int,bool)"
The Signal and slots pattern is little more than an abstraction for
languages that do not support delegates (and dynamic arrays). Which is
not the case for D:
// Declare a signal:
void delegate(Button, int)[] someSignal;
// Connect a slot to a signal:
someSignal ~= foo.someSlot;
// emit the signal
foreach(dg; someSignal)
dg(myButton, myInt);
The only limitation I see with D so far, is on the emit part. You
can't create an emit function that works like this:
emit(someSignal, myButton, myInt);
and that would do the same as that foreach. Because you cannot do
"parameterized"(whether compile time or runtime) function calls.
Automatic S/S disconnection at object destructions should also be
implemented, usually, which requires the use of a base class.
I see, so a S/S object also knows which signals point to his slots.
Still, a base class is not required, a mixin can do the job nearly as well.
I think everybody will agree if I say that the optimal solution would be
D supporting S/S mechanism directly.
I disagree. If D can support S/S without additional languages
constructs, and with nearly the same easy of use as Qt's, then that's
enough.
It would make using of signals/slots as easy as calling of functions,
for instance. But if Walter (and D community) thinks that the S/S
With a library, in D, S/S can be used as easy as calling functions.
--
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
↑ ↓ ← → Kristian <kjkilpi gmail.com> writes:
On Sun, 03 Sep 2006 20:08:36 +0300, Kristian <kjkilpi gmail.com> wrote:
On Sun, 03 Sep 2006 13:01:28 +0300, Bruno Medeiros =
<brunodomedeiros+spam com.gmail> wrote:
Kristian wrote:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It bea=
[snip]
Ludger wrote:
I think there are benefits / downsides to both options of language and=
library implementation. Personally I favor a library option, and if it=
would be included in some (de facto or official) standard library that=
would be good indeed.
In C++ the existing library solutions are very nice and prove that a =
preprocessor like QT uses is not needed at all. I think it can be done=
in D even better, because of delegate support and template features.
The benefit of a library solution is less language bloat, more =
flexible and possible competition. Some libraries also perhaps don't=
want to use the signal-slot mechanism, like harmonia which prefers to =
use sinking-bubbling.
Bruno Medeiros wrote:
I see, so a S/S object also knows which signals point to his slots. =
Still, a base class is not required, a mixin can do the job nearly as =
well.
I think everybody will agree if I say that the optimal solution would=
be D supporting S/S mechanism directly.
I disagree. If D can support S/S without additional languages =
constructs, and with nearly the same easy of use as Qt's, then that's =
enough.
Well, I think the key sentence here is "almost as easy as". Will it be =
easy enough for the majority?
The S/S mechanism is a very simple structure. If you build it 'right', =
then there is no room for competition (because you cannot make it =
simplier). And being simple, it won't bloat the language. Instead it'll =
=
extend the language 'naturally'.
Mixins and templates would make the mechanism quite complex. That would =
=
bloat the *code*.
For example:
/* ----- Qt-styled way with some modifications */
class Foo {
void setValue(int value) {
...
emit valueChanged();
emit valueChanged(oldVal, value);
}
signal valueChanged();
signal valueChanged(int oldValue, int newValue);
}
class Bar {
this() {
foo =3D new Foo;
connect foo.ValueChanged() to handleFoo();
foo2 =3D new Foo;
connect foo2.valueChanged(int, int) to handleFoo(int, int);
}
void handleFoo() {...}
void handleFoo(int oldValue, int newValue) {...}
Foo foo, foo2;
}
/* ----- dcouple-styled way */
// The Widget class implements the S/S handling.
// It's derived from dcouple's SignalSlotManager.
// Its implementation is omited here.
class Foo : Widget {
this() {
sigValueChanged1 =3D new Signal!()(this);
sigValueChanged2 =3D new Signal!(int, int)(this);
}
void setValue(int value) {
...
sigValueChanged1.emit();
sigValueChanged2.emit(oldVal, value);
}
Signal!() sigValueChanged1;
Signal!(int, int) sigValueChanged2;
}
class Bar : Widget {
this() {
foo =3D new Foo;
slotHandleFoo1 =3D new Slot!()(this, &handleFoo1);
connect(foo.sigValueChanged1, slotHandleFoo1);
foo2 =3D new Foo;
slotHandleFoo2 =3D new Slot!(int, int)(this, &handleFoo2);
connect(foo2.sigValueChanged2, slotHandleFoo2);
}
void handleFoo1() {...}
void handleFoo2(int oldValue, int newValue) {...}
Slot!() slotHandleFoo1;
Slot!(int, int) slotHandleFoo2;
Foo foo, foo2;
}
I am not saying that dcouple is poorly written or anything (far from it!=
), =
but the benefits of the direct support is obvious IMHO:
- Less code (and less potential bugs).
- Clearer syntax which is easier to read/write.
- Signals can be connected to any object and function.
- No need to use a base class (or mixins).
- Function overloads can be used.
- Guaranteed to be bug free.
↑ ↓ ← → Lutger <lutger.blijdestijn gmail.com> writes:
Kristian wrote:
<snip>
Bruno Medeiros wrote:
I see, so a S/S object also knows which signals point to his slots.
Still, a base class is not required, a mixin can do the job nearly as
well.
I think everybody will agree if I say that the optimal solution would
be D supporting S/S mechanism directly.
I disagree. If D can support S/S without additional languages
constructs, and with nearly the same easy of use as Qt's, then that's
enough.
Well, I think the key sentence here is "almost as easy as". Will it be
easy enough for the majority?
The S/S mechanism is a very simple structure. If you build it 'right',
then there is no room for competition (because you cannot make it
simplier). And being simple, it won't bloat the language. Instead it'll
extend the language 'naturally'.
Mixins and templates would make the mechanism quite complex. That would
bloat the *code*.
Of course you are right that built-in S/S can be cleaner (and more
efficient), IIRC C#'s events are something like it. But it also has some
disadvantages, for example boost::signals is quite different than QT's,
and the latter also has features for introspection. These libraries (as
a whole) are higher-level than is reasonable for D to incorporate into
the language.
I'm also not saying that dcouple is poorly written, but I think it can
be done a little clearer. This thread inspired me to work on the managed
part of my sigslot module, below I've added how your example looks like
in it. It also handles other callable types (like free functions). There
is no need to derive from any class or interface.
class Foo {
void setValue(int value) {
...
valueChanged1();
valueChanged2(oldVal, value);
}
Signal!() valueChanged1;
Signal!(void, int, int) valueChanged2;
}
class Bar {
this() {
foo = new Foo;
foo.valueChanged1.connect(handleFoo(), this);
foo2 = new Foo;
foo2.valueChanged2.connect(handleFoo(), this);
}
void handleFoo() {...}
void handleFoo(int oldValue, int newValue) {...}
Foo foo, foo2;
mixin SlotObjectDestructor;
}
For example:
/* ----- Qt-styled way with some modifications */
class Foo {
void setValue(int value) {
...
emit valueChanged();
emit valueChanged(oldVal, value);
}
signal valueChanged();
signal valueChanged(int oldValue, int newValue);
}
class Bar {
this() {
foo = new Foo;
connect foo.ValueChanged() to handleFoo();
foo2 = new Foo;
connect foo2.valueChanged(int, int) to handleFoo(int, int);
}
void handleFoo() {...}
void handleFoo(int oldValue, int newValue) {...}
Foo foo, foo2;
}
/* ----- dcouple-styled way */
// The Widget class implements the S/S handling.
// It's derived from dcouple's SignalSlotManager.
// Its implementation is omited here.
class Foo : Widget {
this() {
sigValueChanged1 = new Signal!()(this);
sigValueChanged2 = new Signal!(int, int)(this);
}
void setValue(int value) {
...
sigValueChanged1.emit();
sigValueChanged2.emit(oldVal, value);
}
Signal!() sigValueChanged1;
Signal!(int, int) sigValueChanged2;
}
class Bar : Widget {
this() {
foo = new Foo;
slotHandleFoo1 = new Slot!()(this, &handleFoo1);
connect(foo.sigValueChanged1, slotHandleFoo1);
foo2 = new Foo;
slotHandleFoo2 = new Slot!(int, int)(this, &handleFoo2);
connect(foo2.sigValueChanged2, slotHandleFoo2);
}
void handleFoo1() {...}
void handleFoo2(int oldValue, int newValue) {...}
Slot!() slotHandleFoo1;
Slot!(int, int) slotHandleFoo2;
Foo foo, foo2;
}
I am not saying that dcouple is poorly written or anything (far from
it!), but the benefits of the direct support is obvious IMHO:
- Less code (and less potential bugs).
- Clearer syntax which is easier to read/write.
- Signals can be connected to any object and function.
- No need to use a base class (or mixins).
- Function overloads can be used.
- Guaranteed to be bug free.
↑ ↓ ← → Kristian <kjkilpi gmail.com> writes:
On Wed, 06 Sep 2006 03:50:02 +0300, Lutger <lutger.blijdestijn gmail.com=
=
wrote:
Kristian wrote:
<snip>
Bruno Medeiros wrote:
I see, so a S/S object also knows which signals point to his slots. =
Still, a base class is not required, a mixin can do the job nearly a=
well.
I think everybody will agree if I say that the optimal solution wou=
be D supporting S/S mechanism directly.
I disagree. If D can support S/S without additional languages =
constructs, and with nearly the same easy of use as Qt's, then that'=
enough.
be easy enough for the majority?
The S/S mechanism is a very simple structure. If you build it 'right=
then there is no room for competition (because you cannot make it =
simplier). And being simple, it won't bloat the language. Instead it'=
extend the language 'naturally'.
Mixins and templates would make the mechanism quite complex. That =
would bloat the *code*.
Of course you are right that built-in S/S can be cleaner (and more =
efficient), IIRC C#'s events are something like it. But it also has so=
disadvantages, for example boost::signals is quite different than QT's=
and the latter also has features for introspection. These libraries (a=
a whole) are higher-level than is reasonable for D to incorporate into=
the language.
I'm also not saying that dcouple is poorly written, but I think it can=
be done a little clearer. This thread inspired me to work on the manag=
part of my sigslot module, below I've added how your example looks lik=
in it. It also handles other callable types (like free functions). The=
is no need to derive from any class or interface.
class Foo {
void setValue(int value) {
...
valueChanged1();
valueChanged2(oldVal, value);
}
Signal!() valueChanged1;
Signal!(void, int, int) valueChanged2;
}
class Bar {
this() {
foo =3D new Foo;
foo.valueChanged1.connect(handleFoo(), this);
foo2 =3D new Foo;
foo2.valueChanged2.connect(handleFoo(), this);
}
void handleFoo() {...}
void handleFoo(int oldValue, int newValue) {...}
Foo foo, foo2;
mixin SlotObjectDestructor;
}
Well now, this is almost like having a direct support! :)
One have to use a mixin and the signal names cannot be overloaded. =
However, these are not big drawbacks at all. Actually the overload thing=
=
is a benefit when connecting: you don't have to define parameter types. =
I =
like the syntax very much indeed; this is a must for Phobos...! ;)
At first I thought that I would like the 'connect()' function to have =
parameters swapped (e.g. "foo.valueChanged1.connect(this, handleFoo());"=
), =
but now I think the current order is better.
BTW, I'm wondering why there is 'void' in "Signal!(void, int, int)"? Is =
it =
intentional?
For example:
/* ----- Qt-styled way with some modifications */
class Foo {
void setValue(int value) {
...
emit valueChanged();
emit valueChanged(oldVal, value);
}
signal valueChanged();
signal valueChanged(int oldValue, int newValue);
}
class Bar {
this() {
foo =3D new Foo;
connect foo.ValueChanged() to handleFoo();
foo2 =3D new Foo;
connect foo2.valueChanged(int, int) to handleFoo(int, int);
}
void handleFoo() {...}
void handleFoo(int oldValue, int newValue) {...}
Foo foo, foo2;
}
/* ----- dcouple-styled way */
// The Widget class implements the S/S handling.
// It's derived from dcouple's SignalSlotManager.
// Its implementation is omited here.
class Foo : Widget {
this() {
sigValueChanged1 =3D new Signal!()(this);
sigValueChanged2 =3D new Signal!(int, int)(this);
}
void setValue(int value) {
...
sigValueChanged1.emit();
sigValueChanged2.emit(oldVal, value);
}
Signal!() sigValueChanged1;
Signal!(int, int) sigValueChanged2;
}
class Bar : Widget {
this() {
foo =3D new Foo;
slotHandleFoo1 =3D new Slot!()(this, &handleFoo1);
connect(foo.sigValueChanged1, slotHandleFoo1);
foo2 =3D new Foo;
slotHandleFoo2 =3D new Slot!(int, int)(this, &handleFoo2);
connect(foo2.sigValueChanged2, slotHandleFoo2);
}
void handleFoo1() {...}
void handleFoo2(int oldValue, int newValue) {...}
Slot!() slotHandleFoo1;
Slot!(int, int) slotHandleFoo2;
Foo foo, foo2;
}
I am not saying that dcouple is poorly written or anything (far from=
it!), but the benefits of the direct support is obvious IMHO:
- Less code (and less potential bugs).
- Clearer syntax which is easier to read/write.
- Signals can be connected to any object and function.
- No need to use a base class (or mixins).
- Function overloads can be used.
- Guaranteed to be bug free.
↑ ↓ ← → Lutger <lutger.blijdestijn gmail.com> writes:
Kristian wrote:
<snip>
Well now, this is almost like having a direct support! :)
One have to use a mixin and the signal names cannot be overloaded.
However, these are not big drawbacks at all. Actually the overload thing
is a benefit when connecting: you don't have to define parameter types.
I like the syntax very much indeed; this is a must for Phobos...! ;)
Well thanks. I'll have to make some more tests before putting it online
somewhere, then I'll see what it's worth.
At first I thought that I would like the 'connect()' function to have
parameters swapped (e.g. "foo.valueChanged1.connect(this,
handleFoo());"), but now I think the current order is better.
It's more consistent with free functions / unmanaged slots:
sig.connect(&fooFunc);
// alternative syntax:
sig ~= { writefln ("hello world"); };
BTW, I'm wondering why there is 'void' in "Signal!(void, int, int)"? Is
it intentional?
Yes, it's the return value of the signature. Normally a signal returns
whatever the last slot returns, if it does. With foreach traversal, you
can do something similar to combiners in boost::signals. See
http://www.boost.org/doc/html/signals.html.
Here's an example:
// sum for Signal!(int, <any type>)
int sum(SIGT, ARGT) (SIGT signal, ARGT arg)
{
int result;
foreach(slot; signal)
result += slot(arg);
return result;
}
↑ ↓ ← → Serg Kovrov <kovrov no.spam> writes:
The approach (simplified), I currently use:
class Foo
{
enum EV {VAL_CHANGED,}
void emit(EV ev) {
auto fn = ev in subscribers;
try { if (fn != null) (*fn)(); }
catch (Exception wtf) { writefln("WTF? %s", wtf); }
}
void sub(EV ev, void delegate() fn) {
subscribers[ev] = fn;
}
int val(int i) {
value = i;
emit(EV.VAL_CHANGED);
return value;
}
int val() {
return value;
}
void delegate()[EV] subscribers;
int value;
}
class Bar
{
this(Foo f) {
foo = f;
foo.sub(Foo.EV.VAL_CHANGED, &receive);
}
void receive() {
writefln("received %d", foo.val);
}
Foo foo;
}
void main()
{
auto f = new Foo();
auto b = new Bar(f);
f.val = 1;
delete b;
f.val = 2;
}
--
serg.
↑ ↓ ← → Agent Orange <no spam.com> writes:
Kristian wrote:
It would be nice if D had a signal/slot mechanism similiar to Qt:
http://doc.trolltech.com/4.1/signalsandslots.html
It's an elegant way to handle messages sent between objects. It beats
event table declarations used by other GUI libraries IMHO.
It would make D a lot more appealing language to write GUI
applications. Think of wxWidgets written in D... ;)
I think it would be quite simple to build a S/S support for a compiler
(at first glance, at least). For example:
The 'Object' class has a pointer to S/S data (it's null if the object
don't currently use signals/slots). S/S data holds a slot list for each
signal. It also holds a list of objects that have slot(s) connected to
this object's signal(s). This list is used to disconnect necessary
slots at a destruction of the object.
When the compiler reads a 'emit X' statement, it will do two things.
First, it generates an id for the signal which is used to retrieve a
correct slot list.
Second, the compiler puts the signal's parameters to the stack as it
would call a corresponding function. Instead, the
'Object._emit_signal(id)' function (or something) is called, where 'id'
is the generated id. (Note that there are no function bodies for
signals.) '_emit_signal()' retrieves the correct slot list, and calls
all the slots (delegates) in it. Finally the parameters are removed
from the stack.
Of course, slots should not modify their parameters so that all the
slots will receive the same parameter values. Hence slots should not
use the 'out type'. There is a market for a 'const type' here... *wink*
Maybe there should be no slot keyword at all as there is in Qt. You
don't need to declare a function to be a slot; all the (virtual)
functions can be used with signals.
Because the return values of all the signals are void, the void
typeword could be removed from signal declarations.
signal clicked();
signals:
clicked();
clicked(int button);
BTW, Qt generates ids for signals as follows:
signals:
void clicked(int button, bool isMoved);
-> the id is a string "clicked(int,bool)"
This is a great idea. Trolltech really has created a new style of event
based programming. Its especially useful for IU systems. The signal slot
pattern is a generalized observer pattern with late binding. The signals
are fired at potential observers and resolved via string identifier at
runtime; this allows a great deal of tool-code integration. signal slot
libraries tend to be a hastle because the observers have to disconnect
from their signals on destruction - you cant fire a signal at a dead
object, but Qts moc makes takes care of all of that incredibly well. in
qt signals and slots are like first class language constructs, and it
becomes less of a hastle and more of an amazingly usefull tool. D would
be just absolutely incredible if it supported signals and slots, or even
just the observer pattern - perhaps something in phobos that hooks into
object destruction.... another option is to create a tool such as
trolltechs moc but even then you would have to require users to link a
library or something; or would be nice to see this attached to something
like ares. signals and slots give you anonymous typesafe callbacks that
allow a whole new level of object oriented abstraction that most people
unfortunately cant fully understand until they use them. walter has said
before he doesnt quite know what signals and slots are. I recently used
Qt on a project and I immediately fell in love with them similarly to
the way I fell for D. A mariage of the two could possibly create an
incredible new style of programming.
|
|