Boost logo

Boost :

From: Jeff Garland (jeff_at_[hidden])
Date: 2006-06-03 18:39:04


First off, thanks to Maarten for working on this -- it's something that
is an important need for many reasons. I'm sorry I haven't had time to
keep up with this in real time, but I have a couple thoughts on this
proposal. I've tried to review the mail in this thread and mostly what
I'm going to say isn't new, but I hope it's enough to help push Maarten
to rethink the inheritance aspect of the proposal.

1) Extension by inheritance

I believe that this approach is fundamentally flawed. I'll say it even
more strongly: I don't believe the library will be accepted into Boost
or TR2 with this approach.

There are several reasons for this view:
   a) goes against the current philosophy of c++ standard library
   b) 'use cases' for runtime/polymorphic extension are minimal
   c) space efficiency

Let's take these one at a time.

1.a) goes against the current philosophy of c++ standard library

Outside of iostreams the use of runtime polymorphism in the std library
is minimal. The other 'value types' (see Kevlin Henney if you don't
know what I mean by this) in the standard library including std::complex
and std::string do not support runtime polymorphism. This extends to
new decimal number types that are also being proposed for the standard:

http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1965.html

This should be enough by itself to rethink the approach. The committee
isn't likely to go against the wisdom of the past/future in this case.

1.b) 'use cases' for runtime/polymorphic extension are minimal

In my experience, a well design value-type usually doesn't need to be
extended. 90% of the use cases are just covered. If users need to
extend they can either wrap the base type or build their own. Numeric
types are the canonical example of a value type.

The proposal and discussion on this point have centered on 2 extension
examples: the unsigned_integer case and modular_integer. As several
people have already pointed out the unsigned_integer example is a flawed
example of using inheritance to restrict the behavior of a subtype (see
Barbara Liskov and others on what is now known as the Liskov
Substitution Principle for more on why this is flawed). The
modular_integer strikes me as a completely different type unrelated to
infinite integer.

I'd also like to echo Dave and others thoughts that an unsigned_integer
type is more appropriately coded as a template layered on the base
infinite integer. The unsigned integer case is an example of a more
general problem of a numeric type with a restricted range. This isn't
just a theory, in date-time I use a template called constrained_value to
wrap basic numeric types to restrict the range of values -- so for
example, you can't construct a month with something outside the range
1-12. Others have extended this approach into very general policy-based
frameworks that allow the creation of types with user specified error
handling, etc.

1.c) Space efficiency

The proposal doesn't really discuss space efficiency, but certainly the
introduction of virtual functions guarantees a less space efficient
representation. My expectation would be that if I do the following:

    integer i(0);

that, depending on the allocator, the space requirements should be about
the same as

    int i(0);

That can't be achieved when the class is polymorphic. Of course this
isn't really an issue for a single integer, but applications that use
large arrays of integers that are mostly small values will suffer.

2) Allocator interfaces

I'm not really an expert on the standard allocator interfaces, but if I
understand the approach it makes use of a singleton strategy. That is,
there is NO way to set the allocator on an instance by instance basis --
it's global as set by activate/deactivate. (Am I misunderstanding the
interface here?) Of course, by itself, this interface is error prone
for application design -- if I have 2 different functions and I forget
to call deactivate (does that restore the previous allocator?) then I
might break another unrelated piece of code. Singletons and global data
are a design problem in general, but especially in today's
multi-threaded multi-processor environments.

Anyway, what needs to be done can likely be templates and I suspect it
will result in a superior solution.

Jeff


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