Boost logo

Boost :

From: Edward Diener (eddielee_at_[hidden])
Date: 2002-12-26 18:45:28

"Douglas Paul Gregor" <gregod_at_[hidden]> wrote in message
> On Thu, 26 Dec 2002, Edward Diener wrote:
> > "Douglas Paul Gregor" <gregod_at_[hidden]> wrote in message
> >
> > > On Tue, 24 Dec 2002, Edward Diener wrote:
> > > > One should be able to order the call of slots when connecting them
to a
> > > > signal by saying that a slot should currently come first or last in
> > > > overall order without having to manually manufacturer low and high
> > > > numbers. This is especially so because disparate slots will not know
> > about
> > > > the group numbers of other slots in a signal-slot system.
> > >
> > > This could be simulated with an appropriate wrapper around the
> > > template parameter. In fact, that is probably the best solution
> > > pay for what you don't use" philosophy).
> >
> > In the doc I am looking at group numbers being passed in the
> > boost::signal<>::connect function. I was thinking along the lines of
> > 'connect(LAST,function_object)' or 'connect(FIRST,function_object)'
> > using negative group numbers in your implementation. I don't know if
> > could be done or how much work it would take to do it.
> The type of the group ordering is a template parameter, so group names
> need not be numbers. To use a syntax such as the one you suggest, one
> could use something like this class template:
> enum sandwich_position { FIRST, MIDDLE, LAST };
> template<typename T>
> class sandwich
> {
> public:
> sandwich(sandwich_position pos) : value()
> {
> switch (pos) {
> case FIRST:
> position = --first;
> break;
> case MIDDLE:
> position = 0;
> break;
> case LAST:
> position = ++last;
> break;
> }
> }
> sandwich(const T& value) : value(value), position(0)
> {
> }
> bool operator<(const sandwich& other) const
> {
> return (position < other.position) ||
> (position == other.position && value < other.value);
> }
> private:
> T value;
> int position;
> static int first;
> static int last;
> };
> template<typename T> int sandwich<T>::first = 0;
> template<typename T> int sandwich<T>::last = 0;
> It's not perfect (integer overflow will be a problem), but the basic
> notion is that we can enforce a first/last ordering using a simple
> wrapper. It should give the syntax and semantics you need.

Looks good. You could provide group values along with positional
requirements in the way you show above.

> > I was surprised that the normal connect, without group numbers, did not
> > the calling of slots in the same order as the connecting to a signal.
> You're probably not the only person surprised by that :(. That property is
> only due to an implementation decision (Signals use a multimap
> internally), and I believe it does not represent the "best" interface we
> could have. It seems that the underlying slot storage model really needs
> to be parameterized: in some cases it is unnecessary to have any slot
> ordering, in other cases a simple ordering suffices (e.g., your FIRST and
> LAST suggestion), and in yet other cases a more powerful scheme (such as
> the one currently implemented) is required.

Agreed. I am glad I am not the only one who was surprised by the normal lack
of ordering. My first thought when reading your doc was that slots should be
called in the order in which they attached themselves to a signal. But of
course a parameterized model would be the most flexible as you say.

> > > > Borland has had a simple signal/slot mechanism in C++ Builder
> > (__closures)
> > > > at least 7 years previous to MS .NET's incarnation. Just thought you
> > should
> > > > know.
> > >
> > > Yes, Borland's event/closure mechanism should be mentioned. (It should
> > > probably also be supported directly in Boost.Function, but that's
> > > matter).
> >
> > Supporting Borland's event/closure mechanism in Boost.Function might
> > supporting an extension to C++. Perhaps Boost doesn't want to do things
> > that if they already have a good pure C++ way of doing things like
> > Boost.Function and Boost.Bind along with Boost.Signal. Also, out of pure
> > interest, Microsoft's latest VC++ .NET has their own __event mechanism
> > extension for unmanaged C++ code which is slightly different than their
> > 'delegate' mechanism for managed C++ .NET code ( and C# of course ).
> There is nothing wrong with supporting an extension, so long as we do not
> require the extension to use the library effectively. It's merely a
> convenience for users that don't mind code that is not fully conformant
> C++. Boost.Function could target .NET delegates and the __events as well,
> if someone wants to contribute code and/or compiler for it :)

The problem is how far out of the way of the C++ standard does one want to
go in a reusable library. I have put out code that uses Borland's __closure
and Microsoft's __event as well as Boost.Function/Boost.Bind, all for event
handling on a simple single event/single handler system ( hadn't discovered
your Boost.Signal yet from lack of reading Boost docs ). I don't know how
much of a win-win system it would be to try to incorporate the Borland
and/or Microsoft extensions into a similar Boost library, as opposed to just
using each one separately depending on the implementation provided. Of
course common code is good as long as the tradeoff is simplicity of use as
well as, for the implementor, simplicity of the underlying implementation

> > I mentioned Borland only because your notes on other signal/slot
> > implementations mentioned .NET 'delegates', which is fairly new, and
> > Borland's '__closure' has been around for many years already. I always
> > it bemusing when people, for whatever reason, ignore Borland's earlier
> > advanced conceptual ideas in favor of Microsoft's similar ones coming
> > years afterward. I think you may know that the person responsible for
> > of the language underpinnings of .NET and C# is the same person
> > for much of the design of Delphi/C++ Builder ( Anders Hejlsberg I
> > his name is, although I may have the spelling wrong ). Anyway, all this
> > nether here nor there as far as Boost goes.
> Ah. I omitted Borland's __closure mechanism from the documentation only
> because it is not a mechanism for multicast callbacks like most
> signal/slot systems. It's more like a subset of Function + Bind (or
> Lambda) and not very much like Signals.

That's true except that Borland's __closure can easily be adapted to
multicast callbacks by using containers of __closure pointers and calling
each __closure handler in turn depending on how one wants to store the
__closure pointers in a container to affect the order in which the handlers
are called. I've already done this in some code I have been working on and
there is no problem with it. Of course it is not as sophisticated as
Boost.Signal in its flexibility to accept any kind of functor. And of course
it's not standard C++.

Boost list run by bdawes at, gregod at, cpdaniel at, john at