On Fri, Dec 2, 2016 at 9:19 AM, Edward Diener
For your review you may wish to consider the following questions:
- What is your evaluation of the design?
The design looks reasonable.
- What is your evaluation of the implementation?
I found the use of typedef's to functions returning inline struct definitions to be overly clever and cryptic to new C++ developers. I also found the lack of static type checking in certain places to be objectionable. The unusual formatting is an important subjective turnoff to potential users. Presumably the goal of the library is to enable users to get the functionality they've been missing. The hurdle of a new formatting style to get used to goes against this goal. Fortunately, this is something easily remedied.
- What is your evaluation of the documentation?
Looked reasonable.
- What is your evaluation of the potential usefulness of the library?
Given the prior existence of Boost.Signals I wouldn't find this library to be useful. There is an important aspect to this review that I want to call out. A signal is a "vocabulary type" in that it is pervasive through systems and frequently used in public interfaces. One of the most important qualities of a vocabulary type is that there be only one of them. Imagine the confusion if we had one thread-safe shared pointer class and another one optimized for single threaded usage, or if we had an suite of different variant types with different tradeoffs. No, there should only be one signal type and Boost.Signal made the correct choice of using a so-called intrusive design. - Did you try to use the library?
Nope.
- How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
I spent a few hours on the review. A small amount of time was reading the documentation and a much longer amount of time was spent pondering the implications of incorporating the library into Boost. - Are you knowledgeable about the problem domain?
Yes. I've used Qt signals, Boost.Signals1, and Boost.Signals2 extensively in various projects.
- Do you think the library should be accepted as a Boost library?
No. -- David Sankel
On Mon, Dec 12, 2016 at 5:19 PM, David Sankel
I found the use of typedef's to functions returning inline struct definitions to be overly clever and cryptic to new C++ developers. I also found the lack of static type checking in certain places to be objectionable.
I am not aware of any place where the library is unsafe in terms of static type checking. Maybe I've missed something? Emil
On Mon, Dec 12, 2016 at 8:27 PM, Emil Dotchevski
On Mon, Dec 12, 2016 at 5:19 PM, David Sankel
wrote: I also found the lack of static type checking in certain places to be objectionable.
I am not aware of any place where the library is unsafe in terms of static type checking. Maybe I've missed something?
Sorry, I misunderstood that part of the tutorial. Please disregard this point.
David Sankel wrote:
There is an important aspect to this review that I want to call out. A signal is a "vocabulary type" in that it is pervasive through systems and frequently used in public interfaces. One of the most important qualities of a vocabulary type is that there be only one of them.
I just started to follow this review, and sadly I only have experience with Qt signals, so cannot really comment on whether adding a second signal type to Boost is a good or a bad thing. The only argument I can extract from your review is that a signal-type is a vocabulary type, and Boost should only have a single signal type. I am missing the why. In particular, since you then argue
Imagine the confusion if we had one thread-safe shared pointer class and another one optimized for single threaded usage,
But I do not need to imagine anything here. Rust has a thread-safe atomic reference counted pointer (Arc) and a non-thread-safe reference counted pointer (Rc) in its tiny standard library. While I've seen users being confused about lots of aspects of Rust, I've never seen anybody confused about when/how to use Arc or Rc. Both complement very well in practice, and arguably this design is a perfect example of C++'s "don't pay for what you don't use".
or if we had an suite of different variant types with different tradeoffs
Recently Boost.Hana was accepted into Boost, with its own tuple type, such that we now have boost::tuple, boost::fusion::tuple, std::tuple, and boost::hana::tuple... So while I agree that having 4 types to do the same thing can be bad, I would really like to hear why do you think that: - Boost.Signals2 signal type chose the right trade-offs, - the trade-offs chosen by Synapse's signal type are not worth the "cost" of having two different signal types in Boost.
On Tue, Dec 13, 2016 at 4:26 AM, Gonzalo BG
David Sankel wrote:
or if we had an suite of different variant types with different tradeoffs
Recently Boost.Hana was accepted into Boost, with its own tuple type, such that we now have boost::tuple, boost::fusion::tuple, std::tuple, and boost::hana::tuple...
I don't think this is a good situation! Hana had other merits that compensated for the drawback of introducing another tuple type. Many organizations avoid Boost for unfortunate situations just like this. So while I agree that having 4 types to do the same thing can be bad, I
would really like to hear why do you think that: - Boost.Signals2 signal type chose the right trade-offs,
In sum, I think the Boost.Signals2 model is easier to understand and use for the common case. They work a lot like function pointers, which are familiar, and the storage model is straightforward to explain. - the trade-offs chosen by Synapse's signal type are not worth the "cost"
of having two different signal types in Boost.
I didn't find a strong motivation for having another signals library with this design in the documentation nor could I come up with it on my own. I could be convinced that we really need this with some compelling motivation though notwithstanding the interface issue I raised. -- David
On Tue, Dec 13, 2016 at 5:38 PM, David Sankel
On Tue, Dec 13, 2016 at 4:26 AM, Gonzalo BG
wrote: David Sankel wrote:
or if we had an suite of different variant types with different tradeoffs
Recently Boost.Hana was accepted into Boost, with its own tuple type, such that we now have boost::tuple, boost::fusion::tuple, std::tuple, and boost::hana::tuple...
I don't think this is a good situation! Hana had other merits that compensated for the drawback of introducing another tuple type. Many organizations avoid Boost for unfortunate situations just like this.
I can't tell if this is a good "situation" without studying each of the boost tuple types. On the face of it, I have to assume that there are good reasons for the different types (this is off-topic, but sometimes even avoiding a dependency on another (large) library is a good reason, especially if each library can use "foreign" tuple types generically.)
So while I agree that having 4 types to do the same thing can be bad, I
would really like to hear why do you think that: - Boost.Signals2 signal type chose the right trade-offs,
In sum, I think the Boost.Signals2 model is easier to understand and use for the common case. They work a lot like function pointers, which are familiar, and the storage model is straightforward to explain.
I agree, Signals2 is a good library.
- the trade-offs chosen by Synapse's signal type are not worth the "cost"
of having two different signal types in Boost.
I didn't find a strong motivation for having another signals library with this design in the documentation nor could I come up with it on my own. I could be convinced that we really need this with some compelling motivation though notwithstanding the interface issue I raised.
Synapse can do things that Signals2 can't, at a cost. Specifically, it can use any user-defined object of any user-defined type as an emitter. In this discussion we already explored the idea of extending Signals2, or even using Signals2 as a back-end for Synapse, rather than introducing a new library, see http://boost.2283326.n4.nabble.com/Synapse-library-review-starts-today-Decem... . Thanks, Emil
David Sankel wrote:
No, there should only be one signal type and Boost.Signal made the correct choice of using a so-called intrusive design.
I'm curious whether you can justify this opinion, because the answer is not
as obvious to me. In fact, on its surface, the non-intrusive design is so
much more flexible that one naturally tends to view it as the correct one.
For example, Boost.Signal works well for this design:
class window
{
private:
// state
public:
window( ... );
~window();
// ...
};
We just need to add a few signals at //...:
signal
No, there should only be one signal type...
Except there isn't; but with Synapse, you can add a bit of scaffolding so that a library that uses its own signal type (or uses no signals at all but some other way of communicating, such as Windows messages or C callbacks) emits Synapse signals. Since you don't need to solve the problem of where to put the signal<> object, this is a relatively easy task. Whether the Synapse approach is clearly better may be arguable; whether it's a legitimate alternative design isn't.
participants (4)
-
David Sankel
-
Emil Dotchevski
-
Gonzalo BG
-
Peter Dimov