From: Karl Nelson (kenelson_at_[hidden])
Date: 2000-12-04 16:13:43
> So we are reaching a consensus that life-time tolerance and
> multi-casting are very useful properties that are worthwhile to offer in
> a Boost library of signals/any_functions, even if this does have serious
> ramifications on the design and implementation of the signals.
Multi-cast and life tolerance is certainly a good goal, but
that is competing with other ideas like multi-thread and
rapid emission speed.
> Whether such consequences are serious enough to warrant two or more
> different kinds of signals, I can not tell. I just hope that the
> "full-scale" multi-casting and life-time tolerant signals will be
> remembered as a worthwhile target.
> My own experience is that such signals often change much of the design
> of a program, because they allow many things to be implemented in an
> easier way with less coupling, than traditionally.
I believe that the current boost discussion got started on the basis
of creating a callback mechanism which worked for the limited case
of plugins for thread safe applications. Cloning is a basic requirement
as the costs of locking the threads to access the shared data
if the sigc style reference counting is user. Even under the best
conditions there would need to be a reference count on every access
to the data shared across the threads, thus a mutex lock/unlock.
That only allows read only access during the callback because
otherwise it would require recursive locks or could create excessive
Further, reverse dependency tracking as done with sigc would be
prohibitively expensive under the cloning situation and
require objects within the system to derive from a common type.
This is because every cloning operation would need to add a record
to the object so that it could be cleaned up. But this list is
potentially a shared resource of multiple threads, thus it contains
another set of locks to be acquired.
Thus the criterion for the boost design which intends to be as
fast as a function call and safe across threads requires requires cloning
and no reverse dependencies.
I fully agree with you that there is use for the sigc++ type of
signal/slots in boost, however, I feel that their current
design is unlikely to be suit the needs of event queues and
multi-cast. I think it would be a serious mistake on their
part to try to build a system to accomplish both the safety
of connection that sigc++ provides and the multi-threading
goals they have.
As with the last time I attempted to submit sigc++ to boost, the
discussions of signal/slot/callback system get muddied in
that everyone wants something different out of the ideal and
most parties don't understand the true nature of the design space allows
for no perfect system to be made. Not to mention the constant
debate of how to name the things because STL took a number of names
for rather primitive versions thus leaving only the most
obscure and nebulous words for this new system to claim. (Add
to this that I think there must be two styles of system and you
really begin eating into the dictionary space.) :-)
Thus as before, when it becomes clear there is a very large number
of competing systems and that the goals of the general class of
systems is going to be different than that of sigc++ and attempts
to meld the ideas is just going to give a compromised and unusable
system I bow out.
Just to summarize here are the competing design spaces
- lifetime safety (req sharing, not cloning)
- multi-cast (req lifetime safety)
- event queuing (req lifetime safety)
- multi-thread ( sharing => slow, or clone)
- fast emission ( cloning)
- fast copy ( sharing )
- numbered types (gives sigc++ style separation, better errors,
- unnumbered types ( gives easy functor copy, more meta coding,
fixed sized system)
- virtuals in templates ( simpler design, more type records, smaller
runtime size )
- factored design for templates ( less type records, smaller compile
size, larger runtime size, better for sharing abstractions)
- hardwired types ( expensive adaptors, minimal redirections)
- sharing (fast copy, smaller run size)
- cloning (slow copy, large run size, more types)
There are loads of bad combinations as well, like cloning with
factorization would mean lose of type info and thus would require
dup() functions thus making for an overly complex system.
Combining these attributes generates radically different systems.
For example sigc 1.0 is (numbered,shared,factored w/ multicast, lifespan)
Thus it is has very small compile size and high levels of abstraction
and arbitrary expandablity. The boost systems have been proposed as
(unnumbered,cloned,hardwired? w/multithread). Neither of which would
make good for lifespan/multicast use.
Given the size of that design space, I think only a focused approach
to carve up enough to make useful and reasonable systems will work,
otherwise they will simply debate features til the end of time. :-)
I am hoping as soon as my sigc-1.1.0 is ready for release, boost
can have a good discussion where we come to accept that the design space
is so large that two systems are required. One would be designed
to safety (sigc++ style) and the other for a bound pointer/function/
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk