Boost logo

Boost :

From: Nathan Myers (ncm_at_[hidden])
Date: 2000-04-15 15:34:31


Tomasz Kowalczyk wrote:
> Nathan Myers wrote:
> > Karl Nelson wrote:
> > > 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 at the expense
> > > of [source] code size.
> >
> > The tradeoffs described above are exactly what we encourage for Boost.
>
> I have thought that boost is not that much considered with
> implementation. What is more important is semantics, elegant
> syntax and complexity requirements.

We like libraries that we can easily afford to use. Having semantics
that correctly match real problems is critical; elegance correlates
well with understandability and maintainability; complexity standards
help us decide whether we can use a component for a big problem.

> > > > - is exception safe,
> > >
> > > Libsigc++ isn't intentionally exception unsafe. If it
> > > has a problem it is fixable.
> >
> > Can somebody point out any exception-unsafety in libsigc++?
>
> Can you guarantee exception-safety of libsigc++ ? If no, then it has
> serious implications for all programs using that library.
 
Exception safety is critically important. If the interface doesn't
interfere, then it's a matter of auditing. (To guarantee exception
safety is nice, but it's not the same as having it.) Before I'll
use libsigc++ or your library I'll inspect them myself -- unless
Dave Abrahams announces he's satisfied.
 
> > > > - 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.
> >
> > Agreed, again.
> >
> > > > - 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.
> >
> > Casting within the implementation of a library is entirely
> > permissible. This is what abstraction is about: hiding the
> > ugly stuff in libraries. It is a serious category error to
> > introduce runtime inefficiencies in a low-level library just
> > to make implementation prettier.
>
> The matters are in fact more complicated. When you specify an interface
> for a library you usually have to provide something called a reference
> implementation. The reference implementation doesn't have to be
> optimized, but it should closely follow the specs and should be
> implemented in an understandable way. Reference implementation is
> necessary for the implementors of optimized versions to understand main
> concepts, key implementation techniques and to ensure uniform behavior.
 
A reference implementation is nice, but so is a production implementation.
If I can have both, that's good, but if I have to choose one I will choose
the latter.

Still, casts that have undefined or implementation-defined results do
interfere with portability, and may make it impossible to say what
code really does. Some casts are well-behaved, and the distinction
is why we have different kinds of casts in C++.
 
> > > > - 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.
> >
> > Independence from STL is definitely a feature in a low-level library.
> > The STL containers make large assumptions about memory usage that are
> > likely to be inappropriate in any particular case.
>
> I am not sure I can agree. Standard containers with default allocators
> are much more likely to be optimized for particular platform and
> compiler than your home-grown lists.
>
> But of course, if there is a need to control how memory is managed, then
> it should be a part of the library interface.

Implementations of std lib containers are optimized for big
problems, for holding thousands or millions of things. There,
control of bulk memory usage may be critical. A program with
more than hundreds of callbacks is likely to be unmanageable for
other reasons, so memory management is probably not something to
parameterize for a callback library, and the data structures
probably should be written assuming few elements.

> > The STL, properly, is a set of requirements lists describing how
> > to write iterators so they will work with standard algorithms.
> > A library that doesn't expose iteration in its interface has no
> > appropriate relationship with the STL.
>
> I did not say STL, but standard library. Apart from standard algorithms,
> standard library contains also standard containers (which are much much
> more widely used than algorithms) and many other things, and you should
> know about it.

The std containers are part of STL, but are just examples. In fact,
many of the algorithms are just examples, too. Some of the iterator
adapters are just examples. Any time a standard component which is
intended as just an example doesn't do precisely what you want, it's
not wrong to implement what you want instead. (std::priority_queue<>
is the most frequently cited examplar.)
 
> When mentioning standard library however, I was talking more about my
> attempt to use STL functors (like bind1st<>, less<>, logical_or<> etc.)
> to implement relational operations between signal arguments. These
> functors are pretty much limited in their functionality, and I found
> myself very proud of forcing them to work to some extent anyway :)

less<> is useful as a default predicate in a template argument.
bind1st<> is an adapter to help apply a standard algorithm to
an existing interface. Using them gratuitously nets no points.
Using them judiciously may give a library more generality at no
runtime cost.

Generality is good when it allows you to re-use code instead of
rewriting it, but it exacts hidden costs. If you're bright enough,
you can discover a million dimensions along which to generalize,
and many of the alternatives interfere. Inappropriate generality
can reduce flexibility by interfering with a generalization that you
later discover is really needed.

None of the above is meant as criticism. I don't even claim that all of
it is directly relevant to any of the code (in either library) under
discussion. This is just my expression of Boost policy as I understand
it, or would like it to be understood.

Nathan Myers
ncm_at_[hidden]


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