Re: short guide on getting started with D
cgenie via Digitalmars-d-learn wrote: Hello, I created a short guide on getting started with D: https://blog.mmksoft.uk/#A%20short%20guide%20on%20getting%20started%20with%20D%20programming This is because I recently I started to explore the language and, having read the forum, I see DUB being discouraged quite often. I would appreciate any remarks. My observations: #1 typo: After that, add this meso.build file: "meso.build" should be "meson.build" #2 Does it matter where the dlang = import... block goes in the meson.build file? I added it after the "test(..." in the first block and it seemed to work, but... #3 where is dep? Is it a file or do I have to create it? I could only get you demo to work by removing the line dependencies: deps from meson.build. Then it created dub.json and dub ran it OK. No need for a reply, just my obvservations from someone who knows a little D and less meson. scot
Re: foreach (i; taskPool.parallel(0..2_000_000)
On Tue, Apr 04, 2023 at 09:35:29PM +, Paul via Digitalmars-d-learn wrote: [...] > Well Steven just making the change you said reduced the execution time > from ~6-7 secs to ~3 secs. Then, including the 'parallel' in the > foreach statement took it down to ~1 sec. > > Boy lesson learned in appending-to and zeroing dynamic arrays in a hot > loop! Best practices for arrays in hot loops: - Avoid appending if possible; instead, pre-allocate outside the loop. - Where possible, reuse existing arrays instead of discarding old ones and allocating new ones. - Use slices where possible instead of making copies of subarrays (this esp. applies to strings). - Where possible, prefer sequential access over random access (take advantage of the CPU cache hierarchy). T -- Famous last words: I *think* this will work...
Re: Virtual method call from constructor
On 4/4/23 00:08, Chris Katko wrote: > dscanner reports this as a warning: > > ```D > struct foo{ > this() >{ >/* some initial setup */ >refresh(); >} > void refresh() { /* setup some more stuff */} > // [warn] a virtual call inside a constructor may lead to unexpected > results in the derived classes > > } > ``` I can understand that error for a class. Is that really a struct? If so, then it looks like a dscanner bug to me. > Firstly, are all calls virtual in a struct/class in D? All functions are by-default virtual only for classes. To note, not the "call" but the function can be virtual. When calls are involved, there can be static binding and dynamic binding. Static binding is when a call is resolved at compile time. Dynamic binding is resolved at run time through the vtbl pointer. > Is this any > different from C++? Yes. In C++, all functions are non-virtual by-default. > IIRC, in C++, a struct cannot have virtual calls, No, structs and classes are functionally exactly the same in C++. The only difference is their default member accessibility: public for structs and private for classes. > and virtual methods are explicit keywords in classes. Yes. > Second, could you give me some case examples where this problem occurs? > Is the issue if I override refresh in a derived class, and the base > class will accidentally use child.refresh()? Yes. :) Here is what I had learned in my C++ days: The vtbl pointer is stamped before the constructor is entered. However, an object is not yet complete without its constructor exiting. The base class's constructor calling a virtual function of its derived part might be disastrous because the derived part is not fully constructed yet. (Well, it is not as disastrous in D because all members have default values by-default.) import std; class Base { void foo() { writeln(__FUNCTION__); } this(int i) { writeln("Entered ", __FUNCTION__); foo(); // <-- THE PROBLEM writeln("Exiting ", __FUNCTION__); } } class Derived : Base { override void foo() { writeln(__FUNCTION__); } this(int i) { writeln("Entered ", __FUNCTION__); super(i); writeln("Exiting ", __FUNCTION__); } } void main() { auto d = new Derived(42); } Here is the (annotated) output: Entered deneme.Derived.this Entered deneme.Base.this deneme.Derived.foo<-- NO! Exiting deneme.Base.this Exiting deneme.Derived.this The highlighted line is a call to a derived function but even the base part of the object is not finished its construction yet. The weird thing is Base is initiating the call but it has no idea even whether it's a part of an inheritance hierarchy, what other types are involved, etc. Ali
Re: foreach (i; taskPool.parallel(0..2_000_000)
On Monday, 3 April 2023 at 23:50:48 UTC, Steven Schveighoffer wrote: So what you need is inside `createSpansOfNoBeacons`, take as a reference a `ref Span[MAX_SPANS]`, and have it return a `Span[]` that is a slice of that which was "alocated". See if this helps. Well Steven just making the change you said reduced the execution time from ~6-7 secs to ~3 secs. Then, including the 'parallel' in the foreach statement took it down to ~1 sec. Boy lesson learned in appending-to and zeroing dynamic arrays in a hot loop!
How do you work with unittest libraries in dub packages?
Recently Dmytro Katyukha brought up an issue in one of my dub packages that is supposed to be used as a library. He even went the whole way and came up with a simple reduced example: https://gitlab.com/gizmomogwai/colored/-/merge_requests/3#note_1341026928. The problem here is, that my dub package uses unit_threaded in the unittest configuration, and only imports unit_threaded in a `version (unittest)` block. Previously I imported unit_threaded only in the individual testfunctions themselves, but I thought to reduce some typing. When my library is now used in another project (that does not depend on unit_threaded) `dub test` seems to still compile my library with the unittest version, but it would not run the unittests of my library. So in the end `dub test` fails for the dependent project (as it is not providing unit_threaded). Is this behavior expected? What would be best practice to work around that? Kind regards, Christian
Re: foreach (i; taskPool.parallel(0..2_000_000)
On 4/4/23 11:34 AM, Salih Dincer wrote: On Tuesday, 4 April 2023 at 14:20:20 UTC, Steven Schveighoffer wrote: parallel is a shortcut to `TaskPool.parallel`, which is indeed a foreach-only construct, it does not return a range. I think what you want is `TaskPool.map`: ```d // untested, just looking at the taskPool.map!(/* your map function here */) (s.iota(len)).writeln; ``` I tried, thanks but it goes into infinite loop. For example, the first 50 of the sequence should have been printed to the screen immediately without waiting. ```d long[50] arr; RowlandSequence_v2 range; auto next(long a) { range.popFront(); return arr[a] = range.front(); } void main() { range = RowlandSequence_v2(7, 2); taskPool.map!next(iota(50))/* s.iota(50) .map!next .parallel//*/ .writeln; } ``` Keep in mind that `arr` and `range` are thread-local, and so will be different states for different tasks. Though I don't really know what you are doing there. -Steve
Re: foreach (i; taskPool.parallel(0..2_000_000)
On Tuesday, 4 April 2023 at 14:20:20 UTC, Steven Schveighoffer wrote: parallel is a shortcut to `TaskPool.parallel`, which is indeed a foreach-only construct, it does not return a range. I think what you want is `TaskPool.map`: ```d // untested, just looking at the taskPool.map!(/* your map function here */) (s.iota(len)).writeln; ``` I tried, thanks but it goes into infinite loop. For example, the first 50 of the sequence should have been printed to the screen immediately without waiting. ```d long[50] arr; RowlandSequence_v2 range; auto next(long a) { range.popFront(); return arr[a] = range.front(); } void main() { range = RowlandSequence_v2(7, 2); taskPool.map!next(iota(50))/* s.iota(50) .map!next .parallel//*/ .writeln; } ``` On Tuesday, 4 April 2023 at 13:18:01 UTC, Ali Çehreli wrote: I don't have time to experiment more at this time but I have the following chapters, which includes some of those other algorithms as well: http://ddili.org/ders/d/kosut_islemler.html I read it, thanks... SDB@79
Re: foreach (i; taskPool.parallel(0..2_000_000)
On 4/4/23 5:24 AM, Salih Dincer wrote: Is it necessary to enclose the code in `foreach()`? I invite Ali to tell me! Please explain why parallel isn't running. parallel is a shortcut to `TaskPool.parallel`, which is indeed a foreach-only construct, it does not return a range. I think what you want is `TaskPool.map`: ```d // untested, just looking at the taskPool.map!(/* your map function here */) (s.iota(len)).writeln; ``` Can't use pipelining with it, because it is a member function. https://dlang.org/phobos/std_parallelism.html#.TaskPool.map -Steve
Re: foreach (i; taskPool.parallel(0..2_000_000)
On 4/4/23 02:24, Salih Dincer wrote: > I don't understand what `foreach()` does :) Hm. I forgot whether 'parallel' works only with 'foreach'. But there are various other algorithms in std.parallelism that may be more useful with range algorithm chains: https://dlang.org/phobos/std_parallelism.html > in Turkish I don't have time to experiment more at this time but I have the following chapters, which includes some of those other algorithms as well: http://ddili.org/ders/d/kosut_islemler.html http://ddili.org/ders/d.en/parallelism.html Ali
Re: What do you think about using Chat GPT to create functions in D?
On Monday, 3 April 2023 at 23:38:52 UTC, Marcone wrote: What do you think about using Chat GPT to create functions in D? Well you can use GitHub Copilot in VSCode, and it is kind of interesting but at the current time seems like a distracting waste of time. It will probably get more useful in a few years. LLMs repeats commonly accepted lies as gospel, so do not expect a well adjusted human-like opinion on anything.
Re: foreach (i; taskPool.parallel(0..2_000_000)
On Monday, 3 April 2023 at 22:24:18 UTC, Steven Schveighoffer wrote: So for example, if you have: ```d foreach(i; iota(0, 2_000_000).parallel) { runExpensiveTask(i); } ``` The foreach is run on the main thread, gets a `0`, then hands off to a task thread `runExpensiveTask(0)`. Then it gets a `1`, and hands off to a task thread `runExpensiveTask(1)`, etc. The iteration is not expensive, and is not done in parallel. On the other hand, what you *shouldn't* do is: ```d foreach(i; iota(0, 2_000_000).map!(x => runExpensiveTask(x)).parallel) { } ``` as this will run the expensive task *before* running any tasks. I don't understand what `foreach()` does :) ```d import std.range, std.algorithm : map; import std.stdio, std.parallelism; //import sdb.sequences : RowlandSequence_v2;/* struct RowlandSequence_v2 { import std.numeric : gcd; long b, r, a = 3; enum empty = false; auto front() => a; void popFront() { long result = 1; while(result == 1) { result = gcd(r++, b); b += result; } a = result; } }//*/ enum BP : long { // s, f, r, b = 7, /* <- beginning s = 178, r = 1993083484, b = 5979250449,//*/ len = 190 } void main() { with(BP) { long[len] arr; auto range = RowlandSequence_v2(b, r); s.iota(len) .map!((a){ range.popFront(); return arr[a] = range.front(); } ) .parallel .writeln; } } /* PRINTS: ParallelForeach!(MapResult!(__lambda3, Result))(std.parallelism.TaskPool, [5, 3, 73, 157, 7, 5, 3, 13, 3986167223, 3, 7, 73], 1) */ ``` Is it necessary to enclose the code in `foreach()`? I invite Ali to tell me! Please explain why parallel isn't running. "Ben anlamıyor, foreach ne yapıyor Kodu `foreach()` içine almak şart mı? Ali'yi davet ediyorum, bana anlatması için! Paralel() niye çalışmıyor, lütfen açıklayın hocam. Mümkünse Türkçe!" in Turkish. SDB@79
Re: Virtual method call from constructor
> Firstly, are all calls virtual in a struct/class in D? In D structs are always value types without a vtable or inheritance. Classes are always reference types with a vtable, but some of the methods may be final and hence not in vtable. > Second, could you give me some case examples where this problem occurs? Is the issue if I override refresh in a derived class, and the base class will accidentally use child.refresh()? Yes. It'll call the entry in the vtable, not the one declared in the class if its overridden. > Third, is there the expectation that you should _never_ call any internal, private, methods inside a constructor? Or do I just call/structure it a different way? No. Do what you need to do. Dscanner is a linter that may be a bit sensitive just in case you didn't realize that the behavior is doing something that you probably haven't considered, which could be problematic.
Virtual method call from constructor
dscanner reports this as a warning: ```D struct foo{ this() { /* some initial setup */ refresh(); } void refresh() { /* setup some more stuff */} // [warn] a virtual call inside a constructor may lead to unexpected results in the derived classes } ``` Firstly, are all calls virtual in a struct/class in D? Is this any different from C++? IIRC, in C++, a struct cannot have virtual calls, and virtual methods are explicit keywords in classes. Second, could you give me some case examples where this problem occurs? Is the issue if I override refresh in a derived class, and the base class will accidentally use child.refresh()? Third, is there the expectation that you should _never_ call any internal, private, methods inside a constructor? Or do I just call/structure it a different way? For a concrete example: I have a particle struct. It makes sense to me, to have initial setup code (placed in the refresh() function) called by this(), that later I can then call again; to reset the struct to an initial state in-memory without re-allocations. I imagine in D that there's probably something like: ```D particles[235] = foo.init; ``` but that blows up in a scenario where I'm only _partially_ resetting the struct data. For example, if I had a bunch of pointers to system modules, those values don't need to be nulled and re-set every time in this(), whereas the physical data like position, velocity, angle, need reset in refresh(). You could architect around that, but I'm trying to learn the language mechanics.