DIP82: static unittest blocks

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Sun Sep 27 08:06:26 PDT 2015


On Sunday, 27 September 2015 at 10:32:00 UTC, Kenji Hara wrote:
> 2015-09-27 14:01 GMT+09:00 Jonathan M Davis via Digitalmars-d < 
> digitalmars-d at puremagic.com>:
>
>> This DIP provides a way to handle unittest blocks inside of 
>> templates which works with ddoc without compiling the unittest 
>> blocks into each instantiation.
>>
>> http://wiki.dlang.org/DIP82
>>
>>
>> At present, we really can't put unittest blocks - including 
>> ddoc-ed unittest blocks - inside of templated types, which has 
>> been a problem for Phobos and came up again just the other day 
>> when someone was helpful and went and tried to turn the 
>> examples in std.datetime's *Interval types in ddoc-ed unit 
>> tests, but we had to reject the changes, because it would have 
>> resulted in those tests being compiled into every 
>> instantiation of those templated types, polluting the code of 
>> anyone who uses them as well as making the Phobos unit tests 
>> take longer to run for no extra benefit whatsoever.
>>
>> So, I wrote up this DIP in the hopes of solving the problem in 
>> a clean and simple manner which fits in well with the existing 
>> language features.
>
>
> Interesting proposal.
>
> Quick questions:
>
> 1. I think the token `static` should be placed at the immediate 
> front of `unittest`
>
>     static unittest { ... }
>     static nothrow unittest { ... }   // NG
>
> It's consistent with the behavior of `static this()` family.

I confess that I've always found it to be inconsistent that 
static constructors required that the static be immediately 
before rather than being allowed before or after and among other 
attributes like would occur with any other function. But if we're 
going to retain that inconsistency with static constructors, it 
doesn't really make things much worse to do the same with 
unnittest blocks.

> 2. Currently the members of template won't be semantically 
> analyzed until it's instantiated. So, when the `static 
> unittest` is enclosed in other blocks, how it works?
>
>     template Foo(T) {
>         // inside conditional compilation blocks:
>         static if (is(T == int)) {
>             static unittest { ... }
>         }
>         version (UserDefinedVersion) {
>             static unittest { ... }
>         }
>         debug (UserDefinedDebugId) {
>             static unittest { ... }
>         }
>
>         // inside block/labeled attributes
>         nothrow {
>             static unittest { ... }
>         }
>         @safe:
>             static unittest { ... }
>
>         mixin("static unittest { ... }");
>         mixin(makeStaticUnittest());
>     }
>
>     string makeStaticUnittest() { return "static unittest { ... 
> }"; }

Well, my first question would be what happens with a ddoc comment 
on a symbol within a template? It works to put ddoc comments on 
symbols inside of templates, so clearly we have to have rules of 
some kind which deal with each of the cases that you have here, 
though I'm not as familiar as I probably should be with which of 
those results in a symbol having its ddoc comment in the 
documentation and which doesn't.

Regardles, it does indeed get a bit interesting. Ideally, I would 
think that all of them save for the static if and mixins would 
act exactly like they would outside of a template, since nothing 
about this is specific to a template instantiation, but if no 
semantic analysis is currently done on a template until it's 
instantiated, then supporting a static unittest inside of a 
version block, debug block, a block for an attribute, or after an 
attribute used like a label would mean that at least some amount 
of semantic analysis would have to occur that doesn't necessarily 
happen now (though again, I wonder how that works with ddoc 
comments). Maybe no semantic analysis is done if no static 
unittest is found inside of them, and if one or more static 
unittest is found inside of them, the minimal amount of semantic 
analysis required to determine whether they get compiled in is 
done?

As for the static if, I don't see how it can work if it depends 
on any template arguments. I would think that it would work 
easily enough like the version blocks and debug blocks and 
whatnot if the condition did not depend on the template 
arguments, but I think that it's clear that if the condition 
depends on the template arguments at all, then any static 
unittest blocks in there aren't going to work and probably should 
be considered errors (even if it's just when the template is 
instantiated and the static if's condition is true).

Now, as to the mixins... It would be nice if they worked, but I 
have a hard time believing that it's reasonable to make them 
work. We would like to be able to have mixins work with ddoc 
comments, since without that, we can't put documentation on code 
that's mixed in. So, if we ever implement that, then it might be 
reasonable to do the same with static unittest blocks. But other 
than that, the result would be that every mixin inside of a 
template would have to be generated just to see whether it had a 
static unittest in it, which is kind of ugly. If the argument to 
mixin required a template argument to generate it, then it could 
clearly be skipped, but if not, then we'd have to generate it 
just to check, which would increase the compilation times for any 
template which did that, which wouldn't exactly be pretty. It 
probably wouldn't be a big deal in general, since in most cases, 
if you're going to mix in code like that, you're probably going 
to want to do it based on one or more template arguments, in 
which case, the compiler would be able to see that it didn't need 
to generate the mixin. Still, it would probably be better to just 
not support mixins like this (at least initially) and possibly to 
make it an error if a static unittest gets mixed in, since it 
would only be mixed in when the template was instantiated.

But even if we did something simple and made it so that static 
unittest blocks couldn't legally go inside of a version block, 
debug block, etc. and that all attributes on it had to be applied 
to it directly in order to have any effect, it would still be an 
improvement over what we have now. I would hope though that we 
could do something similar to what we do with ddoc comments 
inside of a template and that the rules that that uses would work 
for this too. But I don't know exactly what those rules are, so I 
don't know how well that will work.

- Jonathan M Davis


More information about the Digitalmars-d mailing list