From: Karl Nelson (kenelson_at_[hidden])
Date: 2000-04-10 02:17:52
--- In boost_at_[hidden], Tomasz Kowalczyk <tomek_at_g...> wrote:
This letter isn't meant as a put down, but rather to inform
that there are far more issues than brought up here. If boost
is really serious about getting a signal slot system, there
is a huge number of trade offs.
I have discussed dozens of systems that people have written
either before seeing libsigc++ or inspired by it. There are
a number of tradeoffs that are not apparent without
a lot of discussion. This is by no means a complete list or
the issues involved. I am always happy to discuss alternative
design choices on my mailing list.
I read the proposed system because it ICEd my 2.95.2 compiler.
Thus I can't be sure of all my info as accurate (I may misread
code.) Also this means I couldn't run my torture suite against
it to see if it handles all the cases.
> Let me state it clearly that it is not my aim to promote one or
> library. I just believe that presented techniques are so widely used
> various forms in different libraries that they deserve more
> from C++ community.
> > Could you tell me why I would use
> > your library and not libsigc?
All of these trade off are disputable at best, because some
of them were done in libsigc++ to avoid problems that you
are ignoring or aren't concerned with. Others complete
wash or totally picky.
> You might consider some reasons, to name a few:
> - doing approximately the same, is about 5 times smaller,
> also unlike libsigc:
5 times the source != 5 times larger. Libsigc++ was written
with a lot of portablity, 2.5 times the callbacks, several entire
adaptor sets you don't even have. Further, libsigc++ was
optimizing for binary size and memory size and the expense
of code size.
> - is exception safe,
Libsigc++ isn't intentionally exception unsafe. If it
has a problem it is fixable.
> - contains headers only, there is no need for linking,
This is by far more of a pitfall than a feature. Libsigc++
uses template factorization which pushes much of the code
into a shared library. Excessive inlining such as your proposal
uses is quite bad.
Further, you mad massive use of virtuals within templates.
Since the dtor for a virtual indicates the location of
typeinfo and other structures then it will place all of
that info in every object file. On many systems this will
result in vastly large binaries. (Yes, they should strip
out redundant typeinfo and virtual tables, but some don't.)
Libsigc++ uses no virtuals to implement callbacks to avoid
the problem. It is a feature.
> - allows to easily connect to a signal anything that can be called
Libsigc++ also has this. Also libsigc++ is entirely open
so adding new functor types is a breeze.
> - allows to copy signal objects - you can store them in a container
Copying signals is a huge dispute on the libsigc++ mailing list.
There is no clear rule to which a signal should be copied. For
example, signal systems set up parent/child relationships, such
as a signal in a class. If a slot connects a signal to its
parents methods and is copied with a new parent should the slots
point to the old or the new? How would a copy screen this
> - avoids circular references by not using reference counting for
Signals in libsigc++ don't reference anything other than the slot
internals. You are confusing the handle/manage() system which was
an experiment/requirement for Gtk--.
> - has no casts in the implementation,
No casts force virtuals into the library. Where is it written
that all good code shouldn't have any casting? Casting is
commonly used in templates to share internals and implementation
and can be done safely and portably.
> - uses standard library where appropriate,
By design libsigc++ depends on nothing, not even STL. Since
STL isn't used in many systems this is a feature. If an when
the quality of STL implementations rises to universal acceptance
and use libsigc++ could be made to use it. Also libsigc++ has
polymorphic list elements which really can't be represented by
STL, so much of it was necessary.
> - makes writing generic code easier by using consistent naming
> (signal<>, signal<A> vs Signal0<>, Signal1<A> etc.)
Libsigc++ is consistant with Gtk-- which is consistant with
Gtk+. That is the cost of starting with one project.
Not having the number means really poor error messages. Good
errors were considered worth the effort. Also your system
completely rules out marshallers and expansion by using
Gtk-- requires up to 6 arguments with marshallers and return
codes. Six arguments would cause yours to give totally
unreadable error messages with signal<foo,void,void,void,void,void>
Marshallers require optional arguments which would force the
user to type out all those voids. And if you need one more
signal/slot argument it is impossible to do with your system.
> To be fair, I have to write what you cannot find in my library:
> - signals returning values
> - user-defined marshaling of arguments
> First was a design decision. Second was a tradeoff, and can be added
You missed portablity. Libsigc++ has a portablity in the template
realm which is unparalleled. It can be ported to gcc 2.7.2 and
Visual C++ 5.0 and still make full use of the library.
Your proposed system doesn't come close to touching what is
required for Gtk--, a vast and complicated library built on
signal/slot concepts. Thus I think your system is more of a
toy than what could be used in a standard.
Now I am not saying that yours should be rejected from boost, (I
am not at all associated with the project) merely there is far
more to consider. I have talked to tons of people who read through
libsigc++ code, felt it was too complicated and sent me a reduced
system of one type or another. However, all thus far have become
convinced that the problem is not nearly as easy and clear cut
as I started exposing the issues.
Also mentioned in a later this thread that libsigc++ contains a nearly
complete thread wrapper. This is with really good reason.
Signal/Slots are anonymous. Thus it is not possible for a user
to thread safe their own code. They don't know all the
receivers nor should they be able to find them out. Thus
any signal/slot system must deal with at least some thread
concepts internally. Also speed was a consideration for libsigc++
at least the first implementation. In order to "void" a return
code you would have to use an exception or a thread safe flag.
A thread safe flag is 40 times faster even when the try/catch is
trivial. You don't have marshallers or returns so you haven't
faced the problem.
(Libsigc++ is still working on a good rwlock which is needed to
make it thread safe.)
Anyway, thanks for another signal/slot system to scrutanize. I
will look it over some more later when I reconsider some of libsigc++
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk