|
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 - Dissecting the SS
↑ ↓ ← → Georg Wrede <georg.wrede nospam.org> writes:
Kyle Furlong wrote:
Walter Bright wrote:
J Duncan wrote:
also as a big fan of QT, Id like to request a S&S mechanism; or some
sort of messaging pattern in the language. I think this would take D
"over the top!"
While I appreciate and enjoy the enthusiasm, this is deja vu all over
again. My entire career in compilers (C, C++, D, Javascript, etc.)
I've heard people say that "if only you implemented X, it will open
the floodgates!" It never does, but what does work is to work with
people who are *already* D users who are blocked by the lack of
something. With S&S, I'd like to see first how far it can be pushed
with existing D techniques.
This last paragraph is why D will succeed. Walter, if this isn't the
best way to evolve a language, I don't know what is.
There are a few excellent implementations already announced around here.
Something I haven't seen discussed is whether we should try to make an
all-encompassing implementation, or maybe separate ones for the
different situations where they might be used.
A stab at dissecting the field:
The environment where SS might be used might be multithreaded or not,
the SS bindings might be entirely known at compile time or be dynamic at
runtime, the participating classes may be known at compile time or only
at runtime (e.g. plugins?).
That gives potentially eight separate use cases:
000 single thread entirely compile time known bindings and classes
001 multithread
010 bindings known only at runtime
011 multithread & bindings only known at runtime
100 classes only known at runtime
101 multithread & classes only known at runtime
110 both bindings & classes only known at runtime
111 multithread & both bindings & classes only known at runtime
Obviously 111 would be the "top". But even after it is implemented, can
there be cases where some of the others would suffice and those cases be
popular enough that implementing them too would be warranted (especially
for simplicity and performance)?
I've played around a little with QT, but that definitely doesn't make me
qualified to answer all of these. :-(
Case 000 would be usable (and sufficient) in round robin simulations.
The cases in between, can it be that some of them simply aren't needed?
Or do people come up with use cases for each one?
---
I'm not seriously suggesting that we implement all 8 separately. But
after this analysis we might get by with say 3 or 4 that should be
popular enough to warrant consideration.
And of course, in any of the cases one can always use 111 instead (just
that it would not be optimal in size and speed for that application).
---
One interesting thing is whether they should really use the same
invocation syntax? The obvious answer is yes, but if we end up
implementing only two or three of them (and especially while they're
still library-only implementations), it may not be imperative at all
that they'd get invoked alike. For example, if we end up with just 111
and 000 permanently, then a dissimilar syntax would in time make it
obvious for the person reading the code which we are using. Knowing this
might release us from coercing the syntax to be alike, especially if
their implementations strongly suggest a dissimilar syntax.
↑ ↓ ← → J Duncan <me nospam.com> writes:
// what QT-style SS would look like in D
class AClass
{
void aSignal(int i);
}
class BClass
{
void aSlot(int i) { writefln("signal triggered %s", i); }
}
void main()
{
AClass a = new AClass;
BClass b = new BClass;
connect( a, "aSignal(int)", b, "aSlot(int)" );
a.aSignal(10); // -> writes "signal triggered 10"
}
i just wanted to give an example of how qt does it. the qt moc generates
the code for the function 'aSignal', this gives it a feeling like its
part of the language. the moc also generates code to map signal and slot
names to addresses. they also provide basic named properties (named data
members with set/get methods) this way. this results in a pretty nice
system that allows things like automatic signal slot connections in gui
classes based on names, (ex. the 'edit1' widget automatically sends a
'textChanged' signal to a slot on a parent widget called
'edit1_textChanged') i dont really have a point to make, i just wanted
to give a simple example of qt.
↑ ↓ ← → Bradley Smith <user domain.invalid> writes:
J Duncan wrote:
// what QT-style SS would look like in D
class AClass
{
void aSignal(int i);
}
class BClass
{
void aSlot(int i) { writefln("signal triggered %s", i); }
}
void main()
{
AClass a = new AClass;
BClass b = new BClass;
connect( a, "aSignal(int)", b, "aSlot(int)" );
a.aSignal(10); // -> writes "signal triggered 10"
}
i just wanted to give an example of how qt does it. the qt moc generates
the code for the function 'aSignal', this gives it a feeling like its
part of the language. the moc also generates code to map signal and slot
names to addresses. they also provide basic named properties (named data
members with set/get methods) this way. this results in a pretty nice
system that allows things like automatic signal slot connections in gui
classes based on names, (ex. the 'edit1' widget automatically sends a
'textChanged' signal to a slot on a parent widget called
'edit1_textChanged') i dont really have a point to make, i just wanted
to give a simple example of qt.
Is there something more to the QT mechanism? I'm not a QT user, but I
figure there must be more too it. Otherwise, why not use the following?
import std.stdio;
class AClass
{
// void aSignal(int i);
void delegate(int) aSignal;
}
class BClass
{
void aSlot(int i) { writefln("signal triggered %s", i); }
}
void main()
{
AClass a = new AClass;
BClass b = new BClass;
//connect( a, "aSignal(int)", b, "aSlot(int)" );
a.aSignal = &b.aSlot;
a.aSignal(10); // -> writes "signal triggered 10"
}
Bradley
↑ ↓ ← → Lutger <lutger.blijdestijn gmail.com> writes:
Bradley Smith wrote:
Is there something more to the QT mechanism? I'm not a QT user, but I
figure there must be more too it. Otherwise, why not use the following?
Yes, J Duncan posted is how it could look like in D. In QT you must
declare signal and slots capable classes with a macro, then QT uses a
custom preprocessor to do all the magic, here is an example from the docs:
class Foo : public QObject
{
Q_OBJECT
public:
Foo();
int value() const { return val; }
public slots:
void setValue( int );
signals:
void valueChanged( int );
private:
int val;
};
void Foo::setValue( int v )
{
if ( v != val ) {
val = v;
emit valueChanged(v);
}
}
Foo a, b;
connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));
b.setValue( 11 ); // a == undefined b == 11
setValue( 79 ); // a == 79 b == 79
b.value(); // returns 79
http://doc.trolltech.com/3.3/signalsandslots.html
↑ ↓ ← → J Duncan <me nospam.com> writes:
Bradley Smith wrote:
J Duncan wrote:
// what QT-style SS would look like in D
class AClass
{
void aSignal(int i);
}
class BClass
{
void aSlot(int i) { writefln("signal triggered %s", i); }
}
void main()
{
AClass a = new AClass;
BClass b = new BClass;
connect( a, "aSignal(int)", b, "aSlot(int)" );
a.aSignal(10); // -> writes "signal triggered 10"
}
i just wanted to give an example of how qt does it. the qt moc
generates the code for the function 'aSignal', this gives it a feeling
like its part of the language. the moc also generates code to map
signal and slot names to addresses. they also provide basic named
properties (named data members with set/get methods) this way. this
results in a pretty nice system that allows things like automatic
signal slot connections in gui classes based on names, (ex. the
'edit1' widget automatically sends a 'textChanged' signal to a slot on
a parent widget called 'edit1_textChanged') i dont really have a point
to make, i just wanted to give a simple example of qt.
Is there something more to the QT mechanism? I'm not a QT user, but I
figure there must be more too it. Otherwise, why not use the following?
import std.stdio;
class AClass
{
// void aSignal(int i);
void delegate(int) aSignal;
}
class BClass
{
void aSlot(int i) { writefln("signal triggered %s", i); }
}
void main()
{
AClass a = new AClass;
BClass b = new BClass;
//connect( a, "aSignal(int)", b, "aSlot(int)" );
a.aSignal = &b.aSlot;
a.aSignal(10); // -> writes "signal triggered 10"
}
Bradley
ok for one, in your example you have a 1 to 1 relationship between
signals and slots; of course this can be done with built in arrays. but
i think the key feature is that A doesnt have to know anything about B,
only that its a qtObject - this provides a whole other level of
anonymous polymorphism. you no longer care about interfaces or base
classes, just if an object has a particular slot. i suppose the key
element missing then would be class introspection.
yeah i found S&S rather silly before i used them, but they quickly
become powerful tools. it seems especially useful in gui code which is
heavily event driven. then you have really slick tool integration. many
mundane tasks are eliminated. you end up just connecting various signals
to slots in a rich class hierarchy to enable various behaviors.....
↑ ↓ ← → J Duncan <me nospam.com> writes:
I also forgot to mention that slots need to disconnect from the signals
when an object is deleted
J Duncan wrote:
Bradley Smith wrote:
J Duncan wrote:
// what QT-style SS would look like in D
class AClass
{
void aSignal(int i);
}
class BClass
{
void aSlot(int i) { writefln("signal triggered %s", i); }
}
void main()
{
AClass a = new AClass;
BClass b = new BClass;
connect( a, "aSignal(int)", b, "aSlot(int)" );
a.aSignal(10); // -> writes "signal triggered 10"
}
i just wanted to give an example of how qt does it. the qt moc
generates the code for the function 'aSignal', this gives it a
feeling like its part of the language. the moc also generates code to
map signal and slot names to addresses. they also provide basic named
properties (named data members with set/get methods) this way. this
results in a pretty nice system that allows things like automatic
signal slot connections in gui classes based on names, (ex. the
'edit1' widget automatically sends a 'textChanged' signal to a slot
on a parent widget called 'edit1_textChanged') i dont really have a
point to make, i just wanted to give a simple example of qt.
Is there something more to the QT mechanism? I'm not a QT user, but I
figure there must be more too it. Otherwise, why not use the following?
import std.stdio;
class AClass
{
// void aSignal(int i);
void delegate(int) aSignal;
}
class BClass
{
void aSlot(int i) { writefln("signal triggered %s", i); }
}
void main()
{
AClass a = new AClass;
BClass b = new BClass;
//connect( a, "aSignal(int)", b, "aSlot(int)" );
a.aSignal = &b.aSlot;
a.aSignal(10); // -> writes "signal triggered 10"
}
Bradley
ok for one, in your example you have a 1 to 1 relationship between
signals and slots; of course this can be done with built in arrays. but
i think the key feature is that A doesnt have to know anything about B,
only that its a qtObject - this provides a whole other level of
anonymous polymorphism. you no longer care about interfaces or base
classes, just if an object has a particular slot. i suppose the key
element missing then would be class introspection.
yeah i found S&S rather silly before i used them, but they quickly
become powerful tools. it seems especially useful in gui code which is
heavily event driven. then you have really slick tool integration. many
mundane tasks are eliminated. you end up just connecting various signals
to slots in a rich class hierarchy to enable various behaviors.....
↑ ↓ ← → Lutger <lutger.blijdestijn gmail.com> writes:
Georg Wrede wrote:
<snip>
A stab at dissecting the field:
The environment where SS might be used might be multithreaded or not,
the SS bindings might be entirely known at compile time or be dynamic at
runtime, the participating classes may be known at compile time or only
at runtime (e.g. plugins?).
That gives potentially eight separate use cases:
000 single thread entirely compile time known bindings and classes
001 multithread
010 bindings known only at runtime
011 multithread & bindings only known at runtime
100 classes only known at runtime
101 multithread & classes only known at runtime
110 both bindings & classes only known at runtime
111 multithread & both bindings & classes only known at runtime
Obviously 111 would be the "top". But even after it is implemented, can
there be cases where some of the others would suffice and those cases be
popular enough that implementing them too would be warranted (especially
for simplicity and performance)?
I'd say yes, but it will depend of how it is actually used. For a lot of
cases, gui perhaps, performance is less important that runtime
connections, but for some things it is the other way around. After
profiling I noticed my non-tracking S&S is 2 to 3 times virtual function
call and tracking is about 5 x the cost, a specialized template for
non-tracking signals would reduce cost even more making it viable for
more use cases.
Syntax matters too, templates can mean it's very clear for the user:
Signal!() signal;
signal ~= { writefln("hello world") };
signal();
For runtime connections, a little more needs to be done I guess.
I would divide the cases in two, each with it's own benefits:
1. Lightweight, compile-time type checked and high-performance. This may
be similar to C# events and is basically a fancy container for delegates
or (preferably) all callable types.
2. Heavy weight, dynamic, with introspection. Slower, this is the QT design.
I think it is possible perhaps to implement 2 on top of 1 with a minimum
of fuss, using D's facilities for compile time string parsing.
|
|