Boost logo

Boost :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2002-02-26 10:17:42


On Tuesday 26 February 2002 06:05 am, you wrote:
> I believe it is important to specified the calling order. I had hoped
> the connection name could be used for specifying this.
>
> I often use signals for signalling that some thing needs to be updated.
> The update sequence is important, because a sub optimal update may course
> screen flicker, or worse one of the slots may have a side effect that
> another slot depends on.
> In my current signal library the calling sequence is last connected first
> signalled. (this way slots that is connected while in a signal-loop is
> not called).
> But it is different to control the connection sequence, because
> the connection points is often spread across the entire program.
> Therefore I was hoping the named-connection system could help control
> the calling order.
>
> I would like if something like the following could be used to
> ensure correct calling order.
>
> class my_button {
> public:
> typedef boost::signal0<
> void,
> boost::signal::last_value, // Note this is why last_value
> // needs to be in the documentation
> int
> std::less< int >
>
> > click_signal_type;
>
> typedef click_signal_type::slot_type click_slot_type;
>
> enum signal_order { early = -10, normal = 0, late = 10 };
>
> boost::connection on_click_connect(
> const click_slot_type& s,
> signal_order n = normal
> ) {
> return on_click.connect(n, s);
> }
>
> private:
> click_signal_type on_click;
> };

Interesting. With a bit of modification to Signals, it would be possible to
use the named connection system as an ordering, but not quite as it is used
above. If I connect two slots, s1 and s2, with the same signal_order value,
the connection of s2 would disconnect s1.

It is possible to implement full ordering control. The ordering would be a
lexicographical ordering of the tuple (priority, name, uniquifier), where:

  1) priority is an integer. if p1 and p2 are priorities, the slot with
priority p1 will execute first if p1 < p2. Default priority is 0.
  2) name is an optional slot/connection name. Named slots with the same
priority will be ordered by name. Unnamed slots will have no name. The names
of all unnamed slots are considered equivalent in the partial order. The
names of unnamed slots precede the names of named slots.
  3) uniquifier is a value used by the implementation to keep unnamed slots
unique. It does not guarantee any ordering for the user.

The above implementation scheme almost entirely dictates implementation via a
map or set, but perhaps that's not a concern. From an efficiency standpoint,
the connection of unnamed slots would become an O(lg n) operation (it was
O(1)), but everything else would be equivalent.

> No, this is unimportant. I was just wondering if there were more
> surprises. Note In our program we have some signals with more then 200
> slots connected, so the complexity of the operations can be very important.
> It would be bad if any operation was O(n*n).

There shouldn't be any surprises that bad, but I'll try to document what I
can (empty() was documented explicitly because it is surprising, and a
departure from STL convention). One reason _not_ to document complexities in
every case is to give implementors the freedom to choose their own data
structures, if this Signals interface were to become standard.

> One other thing. It may be a good idea to make the default slot name a int.
> I don't know the slot implementation, but I think it will make the signal
> more effective (memory and cpu). And I don't think named connections will
> be used very often. And when they are, I will prefer a enum value.
>
> Soren

Changing the slot name type shouldn't affect much, because all slot names are
actually stored in boost::any internally. This avoids having to instantiate
std::map<SlotName, connection, SlotNameCompare> for each (SlotName,
SlotNameCompare) pair.

        Doug


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk