Re: Options for unit testing in D?
On Saturday, 22 June 2019 at 13:51:10 UTC, Paul Backus wrote: On Friday, 21 June 2019 at 22:35:55 UTC, Mike Brockus wrote: On Friday, 21 June 2019 at 17:52:43 UTC, Mike Wey wrote: On 21-06-2019 06:08, Mike Brockus wrote: [...] If you are using the D unittests in your source you can recompile the same source with `d_unittest: true`, the appstream-generator project does this: https://github.com/ximion/appstream-generator/blob/master/src/asgen/meson.build#L108 Or you can keep the tests separate and compile these test separately like you are doing in your C project. I use this option in the GlibD project: https://github.com/gtkd-developers/GlibD/blob/master/tests/gobject/meson.build So to use D 'unittest' I am required to include the main.d module file in the tester executable? If you pass the `-main` flag to the compiler when building your tester executable, it will add an empty main function for you. For example: dmd -unittest -main mymodule.d I think we made a lot of progress, suddenly it's working and I don't need to include main. Is there a way to indicate based on console output that one executable is the tester and the other is the application? test_exe = executable('test_exe', sources: [ 'test.d' ], d_args: [ '-main' ], d_unittest: true, include_directories: exe_dir)
Re: Best practices of using const
On Wednesday, 13 February 2019 at 16:40:18 UTC, H. S. Teoh wrote: So ironically, the iron-clad semantics of D's const system turns out to be also its own downfall. Such things are not ironic. There is always a trade off. You get nothing for free in this universe. Physics tells us this. Conservation laws apply to energy and everything is energy. Hence your computer cannot violate these laws nor can the D specification(whatever it ends up meaning) nor can the D const system, so to speak... That is, any time there something is inversely related to something else then there will be a conservation relationship. If you restrict something too much then something else in direct opposition is becoming too unrestricted. It's not that D's const system is bad, it is that it creates too much restriction without any other option. The usual way too solve these problems is granularity. this way you can choose the right tool for the job. Maybe D needs different levels of const. constN where constN can always be cast to constn for n <= N. One would need to properly define the levels to maximize utility and minimize the granularity. D probably only needs 3-5 levels to be effective.
Re: Closures and memory allocation
On Saturday, 22 June 2019 at 16:52:07 UTC, Anonymouse wrote: When entering the following function, does it allocate: 1. 0 times, because while there are closures defined, none is ever called? 2. 2 times, because there are closures over two variables? 3. 20 times, because there are 20 unique closures? 4. One time, allocating a single closure for all variables referenced in nested functions. Easy to check by inspecting the generated asm (https://run.dlang.io/is/qO3JxO): void receive(void delegate() a, void delegate() b) {} void foo() { int i; long l; void foo1() { i += 1; } void foo2() { l += 1; } receive(, ); } When adding `scope` to the `receive()` params, the closure is allocated on the stack.
Re: Closures and memory allocation
On Saturday, 22 June 2019 at 19:26:13 UTC, Cym13 wrote: On Saturday, 22 June 2019 at 16:52:07 UTC, Anonymouse wrote: [...] Clearly this is a good time for you to learn about the tools D offers to profile allocations. There is the --profile=gc DMD argument that you can use but here there's something better: DMD's GC has a few hooks that are directly inside druntime and therefore available to any D program. [...] Ooops, sorry I went a bit fast there, --DRT-gcopt gives you the number of collections, not allocations.
Re: Closures and memory allocation
On Saturday, 22 June 2019 at 16:52:07 UTC, Anonymouse wrote: I'm looking into why my thing does so many memory allocations. Profiling with kcachegrind shows _d_allocmemory being called upon entering a certain function, lots and lots of times. It's a function that receives concurrency messages, so it contains nested functions that close over local variables. Think receiveTimeout(0.seconds, , , , ...) with 13 pointers to nested functions passed. When entering the following function, does it allocate: 1. 0 times, because while there are closures defined, none is ever called? 2. 2 times, because there are closures over two variables? 3. 20 times, because there are 20 unique closures? Clearly this is a good time for you to learn about the tools D offers to profile allocations. There is the --profile=gc DMD argument that you can use but here there's something better: DMD's GC has a few hooks that are directly inside druntime and therefore available to any D program. Putting your above code in test.d you can then do: $ dmd test.d $ ./test --DRT-gcopt=profile:1 Number of collections: 2 Total GC prep time: 0 milliseconds Total mark time: 0 milliseconds Total sweep time: 0 milliseconds Max Pause Time: 0 milliseconds Grand total GC time: 0 milliseconds GC summary:1 MB,2 GC0 ms, Pauses0 ms <0 ms And here is your answer: two allocations. More information about --DRT-gcopt there: https://dlang.org/spec/garbage.html
Closures and memory allocation
I'm looking into why my thing does so many memory allocations. Profiling with kcachegrind shows _d_allocmemory being called upon entering a certain function, lots and lots of times. It's a function that receives concurrency messages, so it contains nested functions that close over local variables. Think receiveTimeout(0.seconds, , , , ...) with 13 pointers to nested functions passed. When entering the following function, does it allocate: 1. 0 times, because while there are closures defined, none is ever called? 2. 2 times, because there are closures over two variables? 3. 20 times, because there are 20 unique closures? void foo() { int i; long l; void foo01(bool b_) { i += 1; } void foo02(string s) { i += 2; } void foo03(int n) { i += 3; } void foo04(float f) { i += 4; } void foo05(double d) { i += 5; } void foo06() { i += 6; } void foo07() { i += 7; } void foo08() { i += 8; } void foo09() { i += 9; } void foo10() { i += 10; } void foo11() { l += 11; } void foo12() { l += 12; } void foo13() { l += 13; } void foo14() { l += 14; } void foo15() { l += 15; } void foo16() { l += 16; } void foo17() { l += 17; } void foo18() { l += 18; } void foo19() { l += 19; } void foo20() { l += 20; } auto f01 = auto f02 = auto f03 = auto f04 = auto f05 = auto f06 = auto f07 = auto f08 = auto f09 = auto f10 = auto f11 = auto f12 = auto f13 = auto f14 = auto f15 = auto f16 = auto f17 = auto f18 = auto f19 = auto f20 = }
Re: Options for unit testing in D?
On Friday, 21 June 2019 at 22:35:55 UTC, Mike Brockus wrote: On Friday, 21 June 2019 at 17:52:43 UTC, Mike Wey wrote: On 21-06-2019 06:08, Mike Brockus wrote: [...] If you are using the D unittests in your source you can recompile the same source with `d_unittest: true`, the appstream-generator project does this: https://github.com/ximion/appstream-generator/blob/master/src/asgen/meson.build#L108 Or you can keep the tests separate and compile these test separately like you are doing in your C project. I use this option in the GlibD project: https://github.com/gtkd-developers/GlibD/blob/master/tests/gobject/meson.build So to use D 'unittest' I am required to include the main.d module file in the tester executable? If you pass the `-main` flag to the compiler when building your tester executable, it will add an empty main function for you. For example: dmd -unittest -main mymodule.d
Re: There is a computer languages benchmark compare site, but no Dlang benchmark. I think they should support D.
On Saturday, 22 June 2019 at 01:27:31 UTC, lili wrote: A nick site, has a lot of languages, unfortunately no dlang in there. https://benchmarksgame-team.pages.debian.net/benchmarksgame/ See https://github.com/kostya/benchmarks
Re: Best practices of using const
On Saturday, 22 June 2019 at 05:10:14 UTC, Yatheendra wrote: It feels disingenous to want to call a caching object even "logically" const. There has to be a scaffolding-based but hopefully generic compromise. I haven't yet tested this belief, but I believe "physical" const is of good use wherever it can be applied. On Friday, 21 June 2019 at 23:39:20 UTC, H. S. Teoh wrote: The problem with this is that you cannot use const(Wrapper). In particular, if you have a function that wants to document that it does not mutate its argument, you cannot write: auto func(in Wrapper data) { ... } because const(Wrapper) does not allow lazy initialization. ... ... "physical" const has to be applicable & good in many/most other use-cases than caching (citation needed). Somehow, wanting to call mutating code on logically const values sounds to be the wrong want. Lazy initialization sounds like it will be a good DIP :-) Generate (once) on (first) read, just like copy (once) on (first) write. But there are other ways. Heavy computation called at most once: bite the bullet, eagerly construct an immutable value ahead of time. "physical" const might have just enough optimization opportunity to offset biting the bullet. Called more than once: same thing.