Sourceforge has been impossible for me to get through to, so in the absence of being able to checkin to CVS, I include the draft doc with some added text. Mostly a summary of the existing practice, grabbed from existing docs. Also some issues noted, and a rough first attempt at the Motivation.
I'm a better editor than writer, I think, so suggestions welcome. Please notify me if Sourceforge stabilizes, in case it's a problem on my end. Regards, CarlTitle: Signals & Slots for Library TR2
Signals & Slots for Library TR2
Document number: NXXXX=05-NNNN
Date: July 26, 2005
Project: Programming Language C++, Library Working Group
Authors: Murray Cumming <murrayc -at- murrayc.com>
Douglas Gregor <doug.gregor -at- gmail.com>
Carl Nygard <cjnygard -at- verizon.net>
Reply-to: One of us
Table of contents
(Fill in when we know the structure)Motivation
Multi-target callbacks in general, uses, etc. We should have a simple example, maybe with some kind of diagram that shows the signal/slot connections in a small GUI application.The Publisher/Subscriber idiom is well known in OOP circles for its ability to allow communication between objects without inducing tight coupling between said objects. This idiom is also generally known as a Callback system, and has been implemented in various flavors by many different libraries. This TR2 Proposal describes an implementation for a type-safe Publisher/Subscriber library.
One example where this idiom is well suited is in the design of a GUI library. The GUI library provides widgets on screen for user interaction. In order for a library client to respond to user input, it must have some way of receiving and acting on user-generated GUI events.
Many possibilities exist, for example one could require user code to derive each widget to specialize the behavior. For example:
class TextWidget;
class MyDateEntry : public TextWidget {
// override the text entry function
void TextEntry(char c) {
if(c == SPECIAL_CHAR){
// Do something special
}else{
TextWidget::TextEntry()
}
}
// Many other overrides
};
This method introduces tight coupling between the client code and the GUI widget classes. As such, it becomes very brittle, and further development of the GUI is strongly confined by existing implementation details.
In contrast, Publisher/Subscriber system provides the GUI library a way to communicate with the GUI library client without inducing strong coupling. The Publisher/Subscriber library provides a way to abstract the events to the basic function signature, and allows any client to subscribe to a Publisher as long as they meet the function signature requirements. Through the use of an intelligent Subscriber proxy object, ptr-to-function, ptr-to-member-function, and function-object are all opaque to the Publisher/Subscriber mechanism. For example:
class TextWidget;
class MyDateEntry {
void TextEntry(char c) {
// do special stuff here
}
void Init() {
TextWidget* widg = GrabOrCreateWidget();
widg->text_entry_signal()->
connect(std::subscriber(*this, &MyDateEntry::TextEntry));
}
};
This design reduces the amount of coupling between
TextWidget
and MyDateEntry
classes and limits
it to the definition of the TextWidget::*_signal()
Publisher objects defined by TextWidget
.
Coalescing return values
Talk about Accumulators.Tracking and automatic disconnection
Talk about trackable, why we want it, etc.Existing practice
There have been a number of implementations of a Signal/Slot
library, notably the Callback library by Rich Hickey, Qt's addition of
signal/slot as C++ "keywords", libsigc++2
by Murray
Cumming and Martin Schulze, Boost.Signals by Douglas Gregor. We'll
summarize best existing practice by looking at
libsigc++2
, Boost.Signals, as well as look at the
commonalities with .NET delegates, and the tr1::function
class.
libsigc++2
and Boost.Signals are implemented very
similarly, having both grown out of the earlier
libsigc++1.2
library written by Karl Nelson and Tero
Pulkkinen. The major concepts of these two libraries are:
signal<>
object which acts as a publisher to provide messages (really function calls) to a list of subscribers (slot<>
objects)slot<>
object which provides an interface to a function, whether it be a member function, ptr-to-function, or function object. Theslot<>
provides the abstraction to the basic function signature -- return value and argument list.connection
object which represents a signal/slot registration, allowing the programmer to disconnect aslot<>
from asignal<>
trackable
base class, which provides the mechanism for automatic signal/slot disconnection when the object is destructed.
libsigc++
sigc::signal<R,Arg1,Arg2,...,ArgN>
signal<>
object is templatized in terms of a return value
type R, and an arbitrary number of argument types
Arg1..N
. The signal<>
object provides
facilities to:
connect()
aslot<>
objectemit(Arg1,Arg2,...,ArgN)
a signal to each of it's connected
slot<>
objects- note the return value of the last slot, or marshall all return
values into a container, and return the result(s) back to the caller
of
emit()
make_slot()
provides aslot<>
object suitable for connection to anothersignal<>
to provide signal-to-signal connection.- provide access to the list of slots, for slot reordering
sigc::slot<R,Arg1,Arg2,...,ArgN>
slot<>
object is templatized in terms of a return value
type R, and an arbitrary number of argument types
Arg1..N
. The slot<>
object provides
facilities to:
- encapsulate a function call to either a ptr-to-function using
sigc::ptr_fun()
, or ptr-to-member-function, or function object usingsigc::mem_fun()
- pass the arguments
Arg1..N
to the function it is wrapping - pass the return value of the function back to the caller
sigc::connection
connection
object encapsulates an existing signal/slot
connection. The connection
provides facilities to:
disconnect()
theslot<>
object from thesignal<>
- temporarily block() the
signal<>
from calling theslot<>
- unblock() the
slot<>
to resume calling theslot<>
- check whether a
connection
is really connected or not
sigc::trackable
trackable
object provides a base class for objects which
either contain signal<>
objects or are connected via
slot<>
objects. The trackable
object
provides facilities to:
- automatically disconnect associated
signal<>
orslot<>
objects upon destruction. - check whether a
connection
is really connected or not
Boost.Signals
boost::signals::signal<R (Arg1,Arg2,...,ArgN)>
signal<>
object is templatized in terms of a function
signature with an arbitrary number of argument types
Arg1..N
. The signal<>
object provides
facilities to:
connect()
aslot<>
objectemit(Arg1,Arg2,...,ArgN)
a signal to each of it's connectedslot<>
objects- note the return value of the last slot, or marshall all return
values into a container, and return the result(s) back to the caller
of
emit()
- group
slot<>
objects in logical groups for orderingslot<>
boost::signals::slot<R (Arg1,Arg2,...,ArgN)>
slot<>
object is templatized in terms of a function
signature with an arbitrary number of argument types
Arg1..N
. The slot<>
object provides
facilities to:
- encapsulate a function call to either a ptr-to-function or
function object. If using a ptr-to-member-function,
boost::bind
must be used to bind the class object to the ptr-to-member-function - pass the arguments
Arg1..N
to the function it is wrapping - pass the return value of the function back to the caller
boost::signals::connection
connection
object encapsulates an existing signal/slot
connection. The connection
provides facilities to:
disconnect()
theslot<>
object from thesignal<>
boost::signals::trackable
trackable
object provides a base class for objects which
either contain signal<>
objects or are connected via
slot<>
objects. The trackable
object
provides facilities to:
- automatically disconnect associated
signal<>
orslot<>
objects upon destruction.
.NET delegates
tr1::function
Impact on the standard
Very little to say here, probably.Proposed text
Unresolved Issues
Number of Arguments
The number of arguments allowed to a signal will be fixed to some arbitrary number. Given that someone somewhere will find that limit inadequate, no matter what limit is chosen, some easy mechanism might be chosen to allow the user to define a signal/slot combination with the desired number of arguments.
libsigc++2
provides
this capability in the form of m4 macros which can be processed into a
header file form.
Boost.Signals implements the signal/slot objects in terms of preprocessor macros, allowing easy customization.
Slot<>
Grouping
Boost.Signals provides a mechanism for grouping slots in some
logical orderly fashion. It has been shown in the Boost.Signals
implementation that this feature causes pain in the implementation,
and the author has expressed a desire to drop this feature from the
TR2 proposal. Perhaps there is a way to build a grouping mechanism in
"user space" code, utilizing a signal-to-signal connection capability
as is provided in libsigc++2
.
References
dgregor Last modified: Tue Jul 26 15:43:05 EST 2005
cjnygard Last modified: Tue Aug 2 13:06:14 EST 2005
* added Existing Practice for libsigc++2 and Boost.Signals, with some commentary * added section for Unresolved Issues, with entries for number of args and grouping * addedto Motivation, expecting rough treatment editorially
_______________________________________________ libsigc-list mailing list libsigc-list@gnome.org http://mail.gnome.org/mailman/listinfo/libsigc-list