C++ guys hate static_if?

H. S. Teoh hsteoh at quickfur.ath.cx
Thu Mar 14 11:55:17 PDT 2013


On Thu, Mar 14, 2013 at 10:20:04PM +0400, Dmitry Olshansky wrote:
> 14-Mar-2013 22:13, H. S. Teoh пишет:
> >On Thu, Mar 14, 2013 at 06:09:26PM +0100, Andrej Mitrovic wrote:
> >>On 3/14/13, bearophile <bearophileHUGS at lycos.com> wrote:
> >>>This is an invalid argument. You can say the same thing for many
> >>>(most?) tests done by the compiler. Unit tests can't be sure to
> >>>verify all code paths inside a function or template.
> >>
> >>No, it must do exactly that. If you have so many paths that you
> >>can't reasonably test all paths then your template or function is
> >>too complicated to begin with. The benefit here of D over C++ is
> >>that unit testing is cheap and doesn't require external libraries.
> >[...]
> >
> >I think you're missing the point. The point is that concepts allow
> >the compiler to deduce template correctness *without* instantiating
> >it with every possible combination of types.
> >
> >Right now, we *don't* have concepts, and therefore the only way to
> >ensure template correctness is to iterate over the exponential number
> >of combinations of template arguments.
> 
> And if you create a library tool to try out all sensible
> combinations would that work for this use case of concepts?
> 
> In essence you transform concept to some specification and feed it
> into a CTFE-able generatopr function. Then take the code out and
> apply mixin it put into a unittest.
> 
> Sounds easy (if only DMD doesn't run out of memory in the process).
[...]

It's certainly possible, I think. Is it worth pursuing? Maybe. Here's a
first crack at it:

We'd need some way of listing (or generating a list of) all
representative template arguments, say for example, a listing that
includes input range, forward range, bidirectional range, etc.. Then we
need a way to generically generate non-trivial instances of these ranges
(otherwise the unittest could only cover trivial instances, like empty
input range, empty forward range, etc., so the template being tested
will not be verified for non-empty ranges!). The result then will be
used to instantiate the template and run it through a battery of tests.

Of course, the ranges themselves have arguments, so you'd need some kind
of listing of representative types: char, int, float, string, etc., and
have a way of generating non-trivial instances of each of these types,
then use them to instantiate the range with. Maybe for each type also
test it for const(T), immutable(T), etc..

Then you'd have to cover nested ranges, so you'd need a way to specify
how deep you want to go (e.g., a recent forward range bug of using =
instead of .save will only manifest itself if you had a nested range of
forward ranges -- you couldn't catch that just by running through
non-nested ranges).

As you can see, this quickly explodes in exponential number of
combinations. So ultimately, maybe we still have to resort to
hand-picked "representative" types.

But we can do better than the current ad-hoc scheme of writing unittests
for whatever combination just occurred to the code writer (which usually
misses a lot of corner cases). We should have a std.unittest module that
contains lists of all numeric types (byte, int, long, float, double,
real, etc.) with their respective non-trivial instances, as well as
representative range types: {arrays, struct ranges, class ranges} x
{input, forward, bidirection, ...}, along with non-trivial instances of
them. Then provide some generic testing functions that iterate over each
of these lists, that user-written unittests can call to instantiate and
test their templates with.

There can also be a way of adding custom types to the lists, that the
generic functions can pick up and include in their combinations to test.

But the important thing is to collect these type lists in a single
place, so that we can, for example, test std.algorithm functions that
expect input ranges with *all* ranges in the input range list, and be
reasonably certain that if it all passes, the chances for any more bugs
are very slim. (Otherwise, std.algorithm.joiner may have good coverage
but std.algorithm.cartesianProduct may have poor coverage, and there's
lots of missed reuse opportunities for the test ranges used by the
unittests.)


T

-- 
Trying to define yourself is like trying to bite your own teeth. -- Alan Watts


More information about the Digitalmars-d mailing list