From: Sebastian Redl (sebastian.redl_at_[hidden])
Date: 2006-05-26 14:16:02
Maarten Kronenburg wrote:
>Thanks for your comments.
>When an implementation is very slow,
>it will not be useful at all, and not be used.
If a compiler ships with a slow standard library, there will be pressure
on the vendor to make a better library. There is no need to specify
complexity bounds that a vendor will do his best to reach anyway.
I think the way integer is specified should follow the guidelines of how
string is specified, as both try to act like a built-in type.
There are no complexity bounds on, say, string::find_first_of, no
requirement that it be O(N+M), where N is the string's length and M the
number of characters being searched for. Yet it is certainly possible to
implement it this way, instead of the naive O(N*M). If the library
vendor is smart and there's a need for speed, it will be implemented in
a good way. If there are tradeoffs between different functions,
different libraries will offer different tradeoffs or a library will
have a compile-time switch to choose. However, by specifying the
complexity of a given function, you're limiting the implementer. This is
particularly significant in a library full of possibly complex
algorithms such as integer.
>Derivation is a part of C++, so in my opinion
>users must be able to derive from class integer
>to make an integer with special properties.
>How would you explain to a user that whatever
>he/she does with integer, derivation is not an option,
>because the destructor does not happen to be virtual.
>This is what it boils down to in the end.
Well, how do you explain it to users of std::string? The class has been
quite happy without virtual destructors.
>Once again I argue that an unsigned integer is an integer,
>and a modular integer is an integer.
You are wrong here. Of course, given the abstract concept of an integer,
an unsigned integer IS-A integer - just as a signed integer is. However,
the integer you specify is not an abstract concept, but a concrete class
- misnamed, actually, because it's a signed integer. (In the same way as
int is assumed to be signed by default.)
You can either make integer abstract and derive signed_integer and
unsigned_integer from it. Or you can make it concrete, follow the core
language in the implicit assumption that it is actually a signed
integer, and not have the IS-A relationship between unsigned_integer and
integer, thus not deriving one from the other. After all, an unsigned
integer IS-NOT-A signed integer.
>An unsigned int is actually a modular int with modulus 2^32.
>When an integer with a certain allocator must be used
>in an expression with an integer with another allocator,
>then run-time polymorphism is the only option.
Where did the allocator come into this discussion? Anyway, compile-time
polymorphism (i.e. templates) is also an option - make all binary or
higher-order operations that work on integers templated on the
allocators of all operands, put the burden of merging the allocation
correctly on the implementers and specify which allocator is used by the
Or do it as std::string does and simply don't allow cross-use of
different allocator types. (This lack of interoperability has often been
cited as a shortcoming, though. The solution here is to make the
allocator runtime-polymorphic, not the integer.)
>The integer as specified will strictly mimic the int.
>As mentioned to others I will add a unspecified-bool
>conversion to be able to use if( x ) with x an integer.
>But making a "basic" integer and then making it a data member
>of a "full" integer, I do not recommend that strategy.
>I recommend to make the interface right and complete
>from the beginning.
Like std::string did? You can't make everyone happy with any interface,
but a minimal interface can at least claim a philosophy.
What C++ lacks here, IMO, is some sort of mixin concept - effectively a
way to call free functions as if they were members of a class.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk