October 22, 2020
On Thursday, 22 October 2020 at 16:18:14 UTC, H. S. Teoh wrote:
> 2) Ddoc's unittests require unittest blocks to be attached to the symbol they're documenting.

The whole unittest as example thing was a mistake anyway. It doesn't actually work at all (stuff can pass the test without being a usable example due to scope contexts) and encourages ugly, unusable examples because they are run as automatic tests instead of you know, actually being written as examples.

If I was in charge of it, the documented ones would have to be like static, in that they don't depend on *any* context - the compiler treats each block like its own pseudo-module and you must import everything you use again (this guarantees you only use public things and must demo a complete example) - and allow them to be decoupled.

In adrdox, I let you tag them with an ID, then embed by id in the prose to insert the example where you want it.

Maybe ddoc could do that too so you have some freedom to move it around even if you reject the static paragraph.

(or y'all ditch horrible ddoc and come to good docs. the water's fine.)
October 22, 2020
On Thursday, 22 October 2020 at 16:19:30 UTC, Meta wrote:
> It just occurred to me that putting `version(none)` on those tests *might* disable them while also ensuring that the tests show up in the documentation

You should just put the examples in the doc comment at that point. (which is really better anyway, that's the way it should have been done from the beginning!!!)
October 22, 2020
On Thursday, 22 October 2020 at 16:18:14 UTC, H. S. Teoh wrote:
> 2) Ddoc's unittests require unittest blocks to be attached to the symbol they're documenting. So you pretty much have no choice, unless you use Phobos StdDdoc hack (ugh):

It seems like the obvious solution is to remove this limitation. For example, maybe the documentation generator should allow you to attach a unittest to any symbol in the same module, regardless of where it appears in the code:

/// Documents: Nullable.get
unittest
{
    /* etc. */
}
October 22, 2020
On Thursday, 22 October 2020 at 16:34:14 UTC, Adam D. Ruppe wrote:
> On Thursday, 22 October 2020 at 16:18:14 UTC, H. S. Teoh wrote:
>> 2) Ddoc's unittests require unittest blocks to be attached to the symbol they're documenting.
>
> The whole unittest as example thing was a mistake anyway. It doesn't actually work at all (stuff can pass the test without being a usable example due to scope contexts) and encourages ugly, unusable examples because they are run as automatic tests instead of you know, actually being written as examples.
>
> If I was in charge of it, the documented ones would have to be like static, in that they don't depend on *any* context - the compiler treats each block like its own pseudo-module and you must import everything you use again (this guarantees you only use public things and must demo a complete example) - and allow them to be decoupled.
>
> In adrdox, I let you tag them with an ID, then embed by id in the prose to insert the example where you want it.
>
> Maybe ddoc could do that too so you have some freedom to move it around even if you reject the static paragraph.
>
> (or y'all ditch horrible ddoc and come to good docs. the water's fine.)

Two pretty great idea. Do you have a bugzilla entry for them by any chance ?
I don't agree with the sentiment that documented unittests are a mistake though: they are a step up from documentation examples, because you are at least guaranteed they compile and pass in the right context. Examples in documentation might not even compile from day 1 because of a typo, or fail to compile when a symbol / language feature is deprecated or removed.

But making them context-independent is definitely an idea worth exploring.
October 22, 2020
On 10/22/20 12:05 PM, Mathias LANG wrote:
> On Thursday, 22 October 2020 at 14:36:11 UTC, Steven Schveighoffer wrote:
>> On 10/22/20 12:04 AM, Mathias LANG wrote:
>>>
>>> First, why on god's green earth are we putting unittests with explicit template instantiation inside a *template* ? `unittest` inside templates are a terrible "feature", and I've never seen a correct usage of it, which would be a unittest that relies on the user-instantiated instance to test that its expectation still holds.
>>
>> I used it in dcollections quite a bit as a way to ensure all integer based types were tested.
>>
>> The advantage here is, I wanted to run the same tests on every integer type. But I wanted the tests to be close to the functions they were testing.
>>
>> But I think this can be done a different way, and it is *really* hard to get this right. Plus, they are going to be run when you instantiate them elsewhere, which is a problem.
> 
> The point was, if the unittest does not depend on the template parameters, it shouldn't be in the template.
> So the following is a correct use of the feature:
> ```
> struct Nullable (T)
> {
>      unittest
>      {
>          Nullable inst;
>          assert(inst.isNull());
>      }
> }
> ```
> While this is not:
> ```
> struct Nullable (T)
> {
>      unittest
>      {
>          Nullable!int inst;
>          assert(inst.isNull());
>      }
> }
> ```
> 
> Because the first one will run for the user instantiation while the second one is independent on the user instantiation (but will run anyway).

Yes, I know. It's exactly what I did:

https://github.com/schveiguy/dcollections/blob/master/dcollections/TreeMap.d#L123

https://github.com/schveiguy/dcollections/blob/master/dcollections/TreeMap.d#L253

> 
>>>
>>> Second, as the title of the post says, *do not catch Error*. Catching `Error` is a sin, a crime, and every catch of `Error` derivative should have you outraged. It is in direct violation of the specs. And obviously, it's also incompatible with scheme that do not throw an `Error`.
>>
>> I disagree with this. How would you test that the assert error is thrown? It seems that your specific case is being hampered by this, but can't you just look at the parameters to see whether you should handle it or not? Like check the file/line and do the normal thing if it's from phobos?
> 
> You do not test for assert error. Assert errors are logic errors, and if they get triggered, all bets are off. Of course, one might find this impractical, because `get` cannot be tested this way. Perhaps that's a sign that `Nullable` should use exceptions, and not `assert`, for this.

You did not answer the question though, the unittest is making sure that an assert error is thrown when you attempt to get a null value. How else do you test for this?

Nullable using exceptions means it can't be used in nothrow code. This argument has been had countless times for many different discussions.

I thought AssertErrors during unit tests are allowed to be caught by the unit test framework? Isn't assert the main tool to test things? If you aren't supposed to catch them ever, how does unittesting work?

> Regarding the workaround: We currently do this, however, testing for it in a cross-platform and generic way is non-trivial. We can do `endsWith` but we have to account for different paths. And there's no guarantee that we won't have false-positive (e.g. ourcustomlib.std.typecons).

Isn't this for finding a bug though? I didn't think you were going to enable the custom assert handler for production. So who cares if it's not neat and clean, get it to work, find the bug, and move on.

>>> In any case, there's two things I really wish we fixed:
>>> - Either ban unittests in templates, deprecate them, or find a way to make this mistake hard to do;
>>
>> What we need is a way to make a static unittest that serves to provide documentation, but is run as if it were outside the template.
> 
> That's something that Andrej Mitrovic brought up during the following discussion. While it would fix this specific instance, the default would still be bad, so I'm not really convinced.

It needs to happen. There's no reason I shouldn't be able to use documented unittests in templates.

Another thing I've advocated for strongly is to not run imported unittests ever, even in templates.

> 
>>> - Deprecate the ability to catch `Error` in code. If it's not supposed to be caught, it shouldn't be so easy to do it;
>>
>> Disagree. This use case you have is very obscure, and it's much less obscure to verify an Error is thrown in a unittest.
>>
> 
> You disagree with the spec then. The spec says that the stack might not be unwound if an `Error` is thrown.

The stack may not be unwound. That doesn't mean the program is in an invalid state, especially if you control all the code you are testing.

For sure, it should be almost never done. But almost never is not never.

> Walter even raised a PR to actually do the optimization the spec promises. In his words:

>> This PR is still the right thing to do. Attempting to unwind when an Error is thrown is a bad idea, and leads to undefined behavior. Essentially, code which relies on such unwinding needs to be fixed.
> 
> Source: https://github.com/dlang/dmd/pull/6896#issuecomment-362855793

That has no relation to this. There are no unwinding tasks.

-Steve
October 22, 2020
On 10/22/20 12:39 PM, Paul Backus wrote:
> On Thursday, 22 October 2020 at 16:18:14 UTC, H. S. Teoh wrote:
>> 2) Ddoc's unittests require unittest blocks to be attached to the symbol they're documenting. So you pretty much have no choice, unless you use Phobos StdDdoc hack (ugh):
> 
> It seems like the obvious solution is to remove this limitation. For example, maybe the documentation generator should allow you to attach a unittest to any symbol in the same module, regardless of where it appears in the code:
> 
> /// Documents: Nullable.get
> unittest
> {
>      /* etc. */
> }

This would be sufficient!

-Steve
October 22, 2020
On Thursday, 22 October 2020 at 19:19:18 UTC, Steven Schveighoffer wrote:
> On 10/22/20 12:39 PM, Paul Backus wrote:
>> /// Documents: Nullable.get
> This would be sufficient!


I don't hate the syntax either, I think I'll steal it for adrdox...
October 22, 2020
On Thursday, 22 October 2020 at 16:30:57 UTC, H. S. Teoh wrote:
> The problem with that is that it quickly falls into the paradox of who watches the watchers.  The next thing you know, I'm asking for a way to test that my code that catches asserts are actually catching asserts.  Next year I'll be asking for code to test my code that tests code that catches asserts. It never ends.

Paradoxes don't exist. Tests are watchers, and practice shows their presence is better than their absence.
October 22, 2020
On Thursday, 22 October 2020 at 17:14:54 UTC, Mathias LANG wrote:
> Do you have a bugzilla entry for them by any chance ?

I don't...

> I don't agree with the sentiment that documented unittests are a mistake though: they are a step up from documentation examples, because you are at least guaranteed they compile and pass in the right context.

That's pretty easy to do outside the language though: extracting code from the generated documentation is trivial and then you can run them through the compiler externally.

Of course that is an extra step so the unittest does have the advantage of being obvious and built in, but the official website could compile them as part of its existing auto test. And it can do it using the same live environment end users actually try, so same imports, same compiler version present on the "try it now" website, etc., for a more accurate test.
October 22, 2020
On 10/21/20 9:04 PM, Mathias LANG wrote:

> *do not catch Error*. Catching
> `Error` is a sin, a crime, and every catch of `Error` derivative should
> have you outraged. It is in direct violation of the specs. And
> obviously, it's also incompatible with scheme that do not throw an `Error`.

That's true but I will recommend catching Error in both of my upcoming DConf Online presentations. :)

1) Thread entry functions should catch and report any Throwable. Otherwise, main thread will see only a timeout and stack trace of the worker will lost.

2) extern(C) D library functions must catch Throwable and return non-zero error code because the caller is highly likely not going to be able to handle the situation. Even when our library function is called from D, meaning that it can handle D exceptions, we cannot be sure that we are in the main thread. (Can we detect that?). If I'm not mistaken, only the main thread dumps stack trace for Error; so, extern(C) function catching and reporting is essential.

Is my thinking correct?

Ali