August 26, 2021

On Thursday, 26 August 2021 at 23:29:20 UTC, Dennis wrote:

>

On Thursday, 26 August 2021 at 09:38:54 UTC, deadalnix wrote:

>

But having main declared twice is some special level of nonsense. In what case could I possibly want two main?

When there's both a main function and the -main flag, should -main do nothing or override the main function with an empty one?

In the -unittest usage, and without some code overriding the runtime's testrunner, these are equivalent outcomes since dmd no longer runs main after unittests:

import std.stdio;
unittest { writeln("unittest"); }
void main() { writeln("main"); }

contrast:

$ dmd -unittest -run ignoremain.d
unittest
1 modules passed unittests

$ gdc -funittest -o not-ignored ignoremain.d
$ ./not-ignored
unittest
main
August 26, 2021

On 8/26/21 12:12 AM, Mathias LANG wrote:

>

On Wednesday, 25 August 2021 at 11:11:24 UTC, Steven Schveighoffer wrote:

>

Disagree. I'm fine with the simple unittest experience, and avoiding putting all this kind of bloat into the runtime.

What bloat ? Is it the amount of code needed, or the binary size that bothers you ?

unittesting code is in the binary whether unittests are run or not. Whether unittests should be run is all decided at runtime.

But also, what I meant is, if you are going to include all the parts to colorize things, that now needs to be part of druntime.

>

For the former, we already have many framework doing this, so there's a real interest in having it, and having it in a single place means that improvements will be centralized, instead of being duplicated. So, less code bloat when you look at the big picture.

This is different, because the language doesn't have to include the framework to do it. You can write this separately.

>

For the later, I've never seen anyone bother about unittest binary size. I don't think we should. And if the unittest framework code ends up in the binary when -unittest is not used, we're doing it wrong.

unittest framework code exists whether we are unittesting or not. And yet more seemingly unrelated "druntime" modules need to be built.

-Steve

August 27, 2021

On Friday, 27 August 2021 at 00:44:03 UTC, Steven Schveighoffer wrote:

>

unittesting code is in the binary whether unittests are run or not. Whether unittests should be run is all decided at runtime.

And that is the root of the problem. Very few people expect or want this.
Let's just make -unittest its own, separate compilation mode, with a different entry point, like it should have been done 15 years ago.

>

But also, what I meant is, if you are going to include all the parts to colorize things, that now needs to be part of druntime.

Considering the above is fixed, this isn't a problem anymore. Either via --gc-sections or similar, or simply by making it a compiler-instantiated template.

>

This is different, because the language doesn't have to include the framework to do it. You can write this separately.

I like that D allows me to do pretty much anything the way I want it. I can override operators to the extent that I can event replicate the special case that is associative array first assignment. That's pure, plain amazing. And it comes without bloat. No runtime indirection, things are "pay-as-you-go".

But when I throw in the -unittest switch (or the -cov or -profile for that matter), I want all the bells and whistles. Give me colors, an ncurses interface, an HTTP server even! Give me the full battery pack. Don't expect everyone and their mother to implement their own testing framework, that's just bonkers.

August 27, 2021

On Thursday, 26 August 2021 at 23:29:20 UTC, Dennis wrote:

>

On Thursday, 26 August 2021 at 09:38:54 UTC, deadalnix wrote:

>

But having main declared twice is some special level of nonsense. In what case could I possibly want two main?

When there's both a main function and the -main flag, should -main do nothing or override the main function with an empty one?

This is the wrong question. When one runs the unittests, they don't care about main. The existance of the main flag is dubious to begin with.

August 27, 2021

On Friday, 27 August 2021 at 07:48:40 UTC, Mathias LANG wrote:

>

But when I throw in the -unittest switch (or the -cov or -profile for that matter), I want all the bells and whistles. Give me colors, an ncurses interface, an HTTP server even! Give me the full battery pack. Don't expect everyone and their mother to implement their own testing framework, that's just bonkers.

Why would you expect a compiler to implement a testing framework?
If the compiler implements the testing framework, any improvement of the testing framework would require an update of the compiler, which is a very large hurdle. (You want colors? You get 50 new language semantic changes for free!)
I think it's much better if the testing framework is implementated separate from anything else. That doesn't mean everybody has to implement it from scratch, just that they should download it from some other location than the compiler website.
Separation of concerns.

(by the way, I'm convinced unittest is a misfeature of the language. Besides the clear downside that is apparent from this thread, it hurts legibility and because of that it actually discourages extensive unittesting)

-Johan

August 27, 2021

On Friday, 27 August 2021 at 10:33:02 UTC, Johan wrote:

>

On Friday, 27 August 2021 at 07:48:40 UTC, Mathias LANG wrote:

>

But when I throw in the -unittest switch (or the -cov or -profile for that matter), I want all the bells and whistles. Give me colors, an ncurses interface, an HTTP server even! Give me the full battery pack. Don't expect everyone and their mother to implement their own testing framework, that's just bonkers.

Why would you expect a compiler to implement a testing framework?

I don't. I expect the runtime to do it. And to give me the tool to override it if I have needs that aren't covered by it. Currently it only does the later.

August 27, 2021

On Friday, 27 August 2021 at 10:33:02 UTC, Johan wrote:

>

On Friday, 27 August 2021 at 07:48:40 UTC, Mathias LANG wrote:

>

But when I throw in the -unittest switch (or the -cov or -profile for that matter), I want all the bells and whistles. Give me colors, an ncurses interface, an HTTP server even! Give me the full battery pack. Don't expect everyone and their mother to implement their own testing framework, that's just bonkers.

Why would you expect a compiler to implement a testing framework?
If the compiler implements the testing framework, any improvement of the testing framework would require an update of the compiler,

It makes for a better default experience, before someone's picked a testing framework and before code's gotten much investment. unittest{} is such a lightweight feature that a single module with a single function may as well have a unittest{} block.

Not too long ago dmd was completely silent on a successful -unittest run. Now it says "1 modules passed unittests" at the end. This improved the default experience and no proper testing frameworks were harmed.

>

I think it's much better if the testing framework is implementated separate from anything else.

That's already the case. silly, "The better test runner for D", is currently the #1 most popular package on https://code.dlang.org/ and has been in the top five for as long as I can remember.

It checks off everyone's complaints in this thread:

  1. don't want to care about main? for historical reasons you still have to version(unittest) it out, but as dub is updated that won't be necessary either.
  2. want colors? It has red and green unicode symbols.
  3. don't want unittests{} blocks cluttering your code? put them in their own modules under tests/ and add "tests/*" to excludedSourceFiles of non-unittest configurations.
  4. with minimal configuration following the README.md, all you have to do is run 'dub test' and add tests over time. It's not the case that everyone needs to write their own testing framework.
  5. it doesn't bloat the normal build. (if you don't move the dependency on silly into your unittest configuration, the empty module adds 88 bytes to your normal build).

silly's another good example of hooking into the runtime's testing support: https://gitlab.com/AntonMeep/silly/-/blob/master/silly.d#L29

>

That doesn't mean everybody has to implement it from scratch, just that they should download it from some other location than the compiler website.
Separation of concerns.

(by the way, I'm convinced unittest is a misfeature of the language. Besides the clear downside that is apparent from this thread,

What clear downside is that? A minor nit about -main? That there's a discussion happening at all?

I fixed the betterC bug that I noticed earlier in https://github.com/dlang/dmd/pull/13025 and progress is being made on deadalnix's complaint in https://github.com/dlang/dmd/pull/13026 , and for years people have been running 'dub test' without worrying about this or running 'dmd -unittest -run module', oops, 'dmd -main -unittest -run module', and getting more of the very gentle on-ramp to unit tests than they ever lost to the oops.

For the usual internet reasons this discussion is occasionally about 15x as heated as warranted, but since there's no fixing that, you shouldn't sweat it either.

August 27, 2021

On Friday, 27 August 2021 at 10:59:54 UTC, Mathias LANG wrote:

>

On Friday, 27 August 2021 at 10:33:02 UTC, Johan wrote:

>

On Friday, 27 August 2021 at 07:48:40 UTC, Mathias LANG wrote:

>

But when I throw in the -unittest switch (or the -cov or -profile for that matter), I want all the bells and whistles. Give me colors, an ncurses interface, an HTTP server even! Give me the full battery pack. Don't expect everyone and their mother to implement their own testing framework, that's just bonkers.

Why would you expect a compiler to implement a testing framework?

I don't. I expect the runtime to do it. And to give me the tool to override it if I have needs that aren't covered by it. Currently it only does the later.

For this discussion I consider the compiler+runtime to be a single entity, but OK: same question, why should the language runtime do it? I find it a large stretch to include full unittesting framework inside the scope of a language runtime's core functionality.
What is so special about unittesting that requires the implementation to be inside the runtime? The downsides are clear to me (and large), what advantage is gained by having it in the language runtime?

-Johan

August 27, 2021

On Friday, 27 August 2021 at 11:15:44 UTC, jfondren wrote:

>

On Friday, 27 August 2021 at 10:33:02 UTC, Johan wrote:

>

(by the way, I'm convinced unittest is a misfeature of the language. Besides the clear downside that is apparent from this thread,

What clear downside is that? A minor nit about -main? That there's a discussion happening at all?

The downside that people expect it to work well.

You may be right that the thread is diverging too far from the OP, so I'll stop :)

-Johan

August 27, 2021

On Friday, 27 August 2021 at 11:33:14 UTC, Johan wrote:

>

On Friday, 27 August 2021 at 11:15:44 UTC, jfondren wrote:

>

On Friday, 27 August 2021 at 10:33:02 UTC, Johan wrote:

>

(by the way, I'm convinced unittest is a misfeature of the language. Besides the clear downside that is apparent from this thread,

What clear downside is that? A minor nit about -main? That there's a discussion happening at all?

The downside that people expect it to work well.

Look at this:

#! /usr/bin/env dub
/++ dub.sdl:
    configuration "release" {
        targetType "executable"
    }
    configuration "unittest" {
        targetType "library"
        dependency "silly" version="~>1.1.1"
    }
+/

T factorial(T)(T number) {
    if (number <= 1)
        return 1;
    else
        return number * factorial!T(number - 1);
}

@("!5") unittest {
    assert(factorial(5) == 120);
}

@("!0 and !1") unittest {
    assert(factorial(0) == 1);
    assert(factorial(1) == 1);
}

version (unittest) {
} else {
    void main(string[] args) {
        import std.conv : to;
        import std.stdio : writeln;

        writeln(args[1].to!int.factorial);
    }
}

Use it like a script:

$ ./fact.d 5; ./fact.d 10
120
3628800

Run its tests (colors lost in translation):

$ dub -q test --single fact.d
 ✓ fact !5
 ✓ fact !0 and !1

Summary: 2 passed, 0 failed in 0 ms

That's not too bad, is it? It can definitely be improved, but none of my Perl scripts have tests in them.

Nevermind the factorial, it's just something I picked out of the pile.