Re: Boneheaded question regarding compilation...
On Tuesday, 2 April 2024 at 18:21:58 UTC, Mike Shah wrote: An easier fix may be perhaps to just use 'dub' and install the glfw dependency. In my talk, I did everything from scratch (my preferred way), though I suspect using dub with glfw-d (https://code.dlang.org/packages/glfw-d) may provide less resistance. glfw-d also provides an OpenGL hello world triangle example: https://github.com/dkorpel/glfw-d/tree/master/examples/triangle-gl It uses bindbc-opengl instead of glad to load OpenGL functions.
Re: Boneheaded question regarding compilation...
On Monday, 1 April 2024 at 21:23:50 UTC, WhatMeWorry wrote: Huge fan of Mike Shah's YouTube videos regarding D and his latest for D conference: https://mshah.io/conf/24/DConf%20%20Online%202024%20_%20The%20Case%20for%20Graphics%20Programming%20in%20Dlang.pdf So I installed github desktop app and cloned his Talks repo. There is a build command commented out at the top of the main.d file which I've been trying to compile, via the command line: C:\Users\kheas\Documents\Talks\2024\dconf_online\hello_triangle>dmd -g -J. main.d ./glad/gl/*.d -L-L/usr/local/lib -L-lglfw3 -of=prog && ./prog Error: cannot find input file `.\glad\gl\*.d` import path[0] = C:\D\dmd2\windows\bin64\..\..\src\phobos import path[1] = C:\D\dmd2\windows\bin64\..\..\src\druntime\import I'm using a Windows 11 machine so I thought that maybe the syntax was for Linux environment. But replacing all the '/' with '\' did not work. An easier fix may be perhaps to just use 'dub' and install the glfw dependency. In my talk, I did everything from scratch (my preferred way), though I suspect using dub with glfw-d (https://code.dlang.org/packages/glfw-d) may provide less resistance.
Re: Boneheaded question regarding compilation...
On Monday, 1 April 2024 at 21:23:50 UTC, WhatMeWorry wrote: Huge fan of Mike Shah's YouTube videos regarding D and his latest for D conference: https://mshah.io/conf/24/DConf%20%20Online%202024%20_%20The%20Case%20for%20Graphics%20Programming%20in%20Dlang.pdf So I installed github desktop app and cloned his Talks repo. There is a build command commented out at the top of the main.d file which I've been trying to compile, via the command line: C:\Users\kheas\Documents\Talks\2024\dconf_online\hello_triangle>dmd -g -J. main.d ./glad/gl/*.d -L-L/usr/local/lib -L-lglfw3 -of=prog && ./prog Error: cannot find input file `.\glad\gl\*.d` import path[0] = C:\D\dmd2\windows\bin64\..\..\src\phobos import path[1] = C:\D\dmd2\windows\bin64\..\..\src\druntime\import I'm using a Windows 11 machine so I thought that maybe the syntax was for Linux environment. But replacing all the '/' with '\\' did not work. Those are indeed Linux parameters and not windows compatible. This can’t be fixed by switching slash styles. You need the appropriate libs and the appropriate linker switches. -Steve
Boneheaded question regarding compilation...
Huge fan of Mike Shah's YouTube videos regarding D and his latest for D conference: https://mshah.io/conf/24/DConf%20%20Online%202024%20_%20The%20Case%20for%20Graphics%20Programming%20in%20Dlang.pdf So I installed github desktop app and cloned his Talks repo. There is a build command commented out at the top of the main.d file which I've been trying to compile, via the command line: C:\Users\kheas\Documents\Talks\2024\dconf_online\hello_triangle>dmd -g -J. main.d ./glad/gl/*.d -L-L/usr/local/lib -L-lglfw3 -of=prog && ./prog Error: cannot find input file `.\glad\gl\*.d` import path[0] = C:\D\dmd2\windows\bin64\..\..\src\phobos import path[1] = C:\D\dmd2\windows\bin64\..\..\src\druntime\import I'm using a Windows 11 machine so I thought that maybe the syntax was for Linux environment. But replacing all the '/' with '\' did not work.
Re: Question on shared memory concurrency
On Monday, 4 March 2024 at 18:08:52 UTC, Andy Valencia wrote: For any other newbie dlang voyagers, here's a version which works as expected using the system memory allocator. On my little i7 I get 1.48 secs wallclock with 5.26 CPU seconds. ... Using a technique I found in a unit test in std/concurrency.d, I managed to share process memory without GC. It counted up to 1,000,000,000 on my low end i7 in: real0m15.666s user0m59.913s sys 0m0.004s import core.atomic : atomicFetchAdd; import std.concurrency : spawn, send, receiveOnly, ownerTid; import core.thread : Thread; const uint NSWEPT = 1_000_000_000; const uint NCPU = 4; void doadd() { auto val = receiveOnly!(shared(int)[]); for (uint count = 0; count < NSWEPT/NCPU; ++count) { atomicFetchAdd(val[0], 1); } ownerTid.send(true); } void main() { static shared int[] val = new shared(int)[1]; // Parallel workers for (int x = 0; x < NCPU; ++x) { auto tid = spawn(); tid.send(val); } // Pick up all completed workers for (int x = 0; x < NCPU; ++x) { receiveOnly!(bool); } assert(val[0] == NSWEPT); }
Re: Question on shared memory concurrency
On Monday, 4 March 2024 at 16:02:50 UTC, Andy Valencia wrote: On Monday, 4 March 2024 at 03:42:48 UTC, Richard (Rikki) Andrew Cattermole wrote: ... I still hope to be able to share memory between spawned threads, and if it isn't a shared ref of a shared variable, then what would it be? Do I have to use the memory allocator? For any other newbie dlang voyagers, here's a version which works as expected using the system memory allocator. On my little i7 I get 1.48 secs wallclock with 5.26 CPU seconds. import core.atomic : atomicFetchAdd; import std.concurrency : spawn; import core.time : msecs; import core.thread : Thread; import core.memory : GC; const uint NSWEPT = 100_000_000; const uint NCPU = 4; void doadd(shared uint *buf) { for (uint count = 0; count < NSWEPT/NCPU; ++count) { atomicFetchAdd(buf[0], 1); } } void main() { shared uint *buf = cast(shared uint *)GC.calloc(uint.sizeof * 1, GC.BlkAttr.NO_SCAN); for (uint x = 0; x < NCPU-1; ++x) { spawn(, buf); } doadd(buf); while (buf[0] != NSWEPT) { Thread.sleep(1.msecs); } }
Re: Question on shared memory concurrency
On Monday, 4 March 2024 at 16:02:50 UTC, Andy Valencia wrote: On Monday, 4 March 2024 at 03:42:48 UTC, Richard (Rikki) Andrew Cattermole wrote: A way to do this without spawning threads manually: ... Thank you! Of course, a thread dispatch per atomic increment is going to be s.l.o.w., so not surprising you had to trim the iterations. Bug I still hope to be able to share memory between spawned threads, and if it isn't a shared ref of a shared variable, then what would it be? Do I have to use the memory allocator? There is `__gshared` type qualifier, but unlike plain `shared` it is up to you to ensure valid concurrency access as stated in the docs. https://dlang.org/spec/const3.html#shared_global
Re: Question on shared memory concurrency
On Monday, 4 March 2024 at 03:42:48 UTC, Richard (Rikki) Andrew Cattermole wrote: A way to do this without spawning threads manually: ... Thank you! Of course, a thread dispatch per atomic increment is going to be s.l.o.w., so not surprising you had to trim the iterations. Bug I still hope to be able to share memory between spawned threads, and if it isn't a shared ref of a shared variable, then what would it be? Do I have to use the memory allocator?
Re: Question on shared memory concurrency
A way to do this without spawning threads manually: ```d import std.parallelism : TaskPool, parallel, taskPool, defaultPoolThreads; import std.stdio : writeln; import std.range : iota; enum NSWEPT = 1_000_000; enum NCPU = 4; void main() { import core.atomic : atomicLoad, atomicOp; shared(uint) value; defaultPoolThreads(NCPU); TaskPool pool = taskPool(); foreach(_; pool.parallel(iota(NSWEPT))) { atomicOp!"+="(value, 1); } writeln(pool.size); writeln(atomicLoad(value)); } ``` Unfortunately I could only use the default task pool, creating a new one took too long on run.dlang.io. I also has to decrease NSWEPT because anything larger would take too long.
Question on shared memory concurrency
I tried a shared memory parallel increment. Yes, it's basically a cache line thrasher, but I wanted to see what's involved in shared memory programming. Even though I tried to follow all the rules to make true shared memory (not thread local) it appears I failed, as the wait loop at the end only sees its own local 250 million increments? import core.atomic : atomicFetchAdd; import std.stdio : writeln; import std.concurrency : spawn; import core.time : msecs; import core.thread : Thread; const uint NSWEPT = 1_000_000_000; const uint NCPU = 4; void doadd(ref shared(uint) val) { for (uint count = 0; count < NSWEPT/NCPU; ++count) { atomicFetchAdd(val, 1); } } void main() { shared(uint) val = 0; for (int x = 0; x < NCPU-1; ++x) { spawn(, val); } doadd(val); while (val != NSWEPT) { Thread.sleep(1.msecs); } }
question about ctfe init importC zero length array of struct
This is the type defined from c code import by importC: ```c struct A { int count; int[] i; } ``` This kind data need to be init as const to avoid runtime cost, and need to be done from D code. how can I do this ? To put code into D source, I can use "-i=package" to automatically import the only need part without rebuild it, and avoid the problem of importC path search. (and there is type wrapper inside D code). I can fix it with a template type, the cost is very slow build time. (because there is a lot diff auto generate type) Any suggestions how to handle this fast and simple ?
Re: question
On Wednesday, 13 December 2023 at 12:49:14 UTC, fred wrote: a bug ? It helps if you explain what you're talking about so we don't have to guess. I tried the code on my computer and it worked fine. But then figuring, you must be saying something doesn't work right, I tried it on another compiler and saw it endlessly loop. So it ended using my dmd 2.098, looped on my dmd 2.105 but this is actually just coincidence. Consider this: --- void s2() { shared(bool) isDone = false; spawn(, ); Thread.sleep(400.msecs); w("done"); isDone = true; } --- The variable `isDone` is temporary; as a local variable, it ceases to exist when s2 returns. So when w2 tries to check if it is done or not, it takes a bit of luck for the memory to still be the same value as it was; it has likely been recycled or otherwise cleared by then. You need to keep the variable alive until *both* threads are done with it, either by doing some fancy synchronization between the threads or just letting the garbage collector manage the shared variable: ``` void s2() { // let the GC do it shared(bool)* isDone = new shared bool; spawn(, isDone); Thread.sleep(400.msecs); w("done"); *isDone = true; } ```
Re: question
On Wednesday, 13 December 2023 at 12:49:14 UTC, fred wrote: [...] a bug ? thanks anyway Try to define the flag as static ```d static shared(bool) isDone = false; ``` I dont know if that should be a compiler error to have local shared (I tend to think yes as locals are specific to a frame, i.e a thread). At least you know how to fix the issue.
question
import core.thread; import std.concurrency; import std.stdio : w = writeln; void w2(shared(bool) *done) { while (*done == false) { Thread.sleep(100.msecs); w("print done? ", *done); } } void s2() { shared(bool) isDone = false; spawn(, ); Thread.sleep(400.msecs); isDone = true; } void main() { s2(); } = a bug ? thanks anyway
Re: 'typeof' question
On Tuesday, 28 November 2023 at 18:43:37 UTC, Adam D Ruppe wrote: On Tuesday, 28 November 2023 at 18:41:49 UTC, DLearner wrote: A* A_Ptr; struct B { int BFld2; typeof(A_Ptr)[0..($-1)] ASUB; // Idea is ASUB of type A, from A_Ptr of type A*. I think what you really want is typeof(*A_Ptr) ASUB; the typeof thing returns the type you'd get from the code inside Thanks - worked.
Re: 'typeof' question
On Tuesday, 28 November 2023 at 18:41:49 UTC, DLearner wrote: A* A_Ptr; struct B { int BFld2; typeof(A_Ptr)[0..($-1)] ASUB; // Idea is ASUB of type A, from A_Ptr of type A*. I think what you really want is typeof(*A_Ptr) ASUB; the typeof thing returns the type you'd get from the code inside
'typeof' question
Trying to manipulate 'typeof' return strings, preferably at compile-time. e.g. to produce struct B below (intended to have an A sub-struct), from A_Ptr alone. ``` struct A { int AFld1; } A* A_Ptr; struct B { int BFld2; typeof(A_Ptr)[0..($-1)] ASUB; // Idea is ASUB of type A, from A_Ptr of type A*. } ``` But this fails with 'can only slice tuple types...'. Suggestions?
Re: Question regarding mir.csv.
On Wednesday, 1 November 2023 at 20:49:16 UTC, Zz wrote: Hi, Currently using std.csv and would like to do the following using mir.csv. auto data = std.csv.csvReader!Layout(input).array; Are there any examples out there on using mir.csv? Regards, Zz you can find some examples in source code: https://github.com/libmir/mir-ion/blob/master/source/mir/csv.d
Question regarding mir.csv.
Hi, Currently using std.csv and would like to do the following using mir.csv. auto data = std.csv.csvReader!Layout(input).array; Are there any examples out there on using mir.csv? Regards, Zz
Re: Question about interface implementation
On Sunday, 21 May 2023 at 11:20:30 UTC, ag0aep6g wrote: On 21.05.23 12:55, Theo wrote: As for the other part, if I use an abstract base class, I *must* indicate when i'm overriding the base class method by explicately saying 'override'. I wouldn't mind if implementing interface methods required `override` as well. I don't know if there is a rationale for the inconsistency. Consistency, which can also aid in self-documenting, might look something like this: - using interface - interface Ship { void setSpeed(int speed); // must 'implement' int getSpeed(); // must 'implement' } class PirateShip : Ship { private(this) int speed = 0; public void setSpeed(int speed) : implements Ship { this.speed = speed; } public int getSpeed() : implements Ship { return speed; } } - using base class - abstract base class Ship { abstract void setSpeed(int speed); // must 'implement' abstract int getSpeed(); // must 'implement' void someotherMethod(); // can 'override'. } class PirateShip : Ship { private(this) int speed = 0; public void setSpeed(int speed) : implements Ship { this.speed = speed; } public int getSpeed() : implements Ship { return speed; } public void someotherMethod() : overrides Ship { } } -
Re: Question about interface implementation
On 21.05.23 12:55, Theo wrote: As for the other part, if I use an abstract base class, I *must* indicate when i'm overriding the base class method by explicately saying 'override'. I wouldn't mind if implementing interface methods required `override` as well. I don't know if there is a rationale for the inconsistency.
Re: Question about interface implementation
On Sunday, 21 May 2023 at 10:33:07 UTC, ag0aep6g wrote: On 21.05.23 12:28, ag0aep6g wrote: Since @trusted functions are guaranteed (by the programmer) to be safe, they are allowed to overload/implement @safe functions/prototypes. *override oh ok. so i can override a @safe interface method with a @trusted implementation of that method, and nobody will ever know. I'm not sure how i feel about that. Likely I would never put @safe in the interface anyway, but even so... As for the other part, if I use an abstract base class, I *must* indicate when i'm overriding the base class method by explicately saying 'override'. Would be nice to have something for an interface method, so when it's being implemented, you know that method is the implementation of an interface method, and not just some method specific to that class - see my idea below. interface Ship { void setSpeed(int speed); int getSpeed(); } class PirateShip : Ship { private int speed = 0; // Here, I really mean 'private(this)' public void setSpeed(int speed) : implements Ship { this.speed = speed; } public int getSpeed() : implements Ship { return speed; } } // other ships.
Re: Question about interface implementation
On 21.05.23 12:28, ag0aep6g wrote: Since @trusted functions are guaranteed (by the programmer) to be safe, they are allowed to overload/implement @safe functions/prototypes. *override
Re: Question about interface implementation
On 21.05.23 11:55, Theo wrote: class MerchantShip : Ship { private int speed = 0; // If only I had 'private(this)' !! // how do I know this method is actually an implementation of an interface method // and not a method specific to this class? // AND ... how come I can change a @safe interface method into a @trusted one? public @trusted void setSpeed(int speed) { int *s = void; // Mmmm.. and my interface all had @safe methods!! this.speed = speed; } [...] } As far as I understand, a method that has the right signature is always an implementation of the interface. There is no way to make a method of the same name, with the same parameters, etc. that is "specific to the class". @trusted means that you're allowed to use @system features in the implementation while the function must follow the restrictions of @safe when called. Since @trusted functions are guaranteed (by the programmer) to be safe, they are allowed to overload/implement @safe functions/prototypes. If you create an @trusted function that is not safe to call, that's an error on your part.
Question about interface implementation
see comments in the code below. they are my questions. But feel free to ignore the comment about 'private(this)' ;-) interface Ship { @safe void setSpeed(int speed); @safe int getSpeed(); } class PirateShip : Ship { private int speed = 0; // If only I had 'private(this)' !! // how do I know this method is actually an implementation of an interface method // and not a method specific to this class? public void setSpeed(int speed) { this.speed = speed; } // how do I know this method is actually an implementation of an interface method // and not a method specific to this class? public int getSpeed() { return speed; } } class MerchantShip : Ship { private int speed = 0; // If only I had 'private(this)' !! // how do I know this method is actually an implementation of an interface method // and not a method specific to this class? // AND ... how come I can change a @safe interface method into a @trusted one? public @trusted void setSpeed(int speed) { int *s = void; // Mmmm.. and my interface all had @safe methods!! this.speed = speed; } // how do I know this method is actually an implementation of an interface method // and not a method specific to this class? // AND ... how come I can change a @safe interface method into a @trusted one? public @trusted int getSpeed() { int *s = void; // Mmmm.. and my interface all had @safe methods!! return speed; } }
Re: quick question, probably of little importance...
On Monday, 1 May 2023 at 03:53:24 UTC, Cecil Ward wrote: On Wednesday, 26 April 2023 at 23:07:39 UTC, WhatMeWorry wrote: [...] Correction: I can’t count. There are only two instructions in parallel with another pair running alongside, not three. The first reg, reg move counts as zero cycles, so the total time is just the sum of the following three instructions’ times, ignoring the other parallel stream.
Re: quick question, probably of little importance...
On Wednesday, 26 April 2023 at 23:07:39 UTC, WhatMeWorry wrote: On Wednesday, 26 April 2023 at 23:02:07 UTC, Richard (Rikki) Andrew Cattermole wrote: Don't forget ``num % 2 == 0``. None should matter, pretty much all production compilers within the last 30 years should recognize all forms of this and do the right thing. Thanks. Fastest reply ever! And I believe across the world? I suppose my examples required overhead of a function call. So maybe num % 2 == 0 is fastest? I made a small change, making the retval a bool rather than an int. I got slightly better code generation with the int, as it seems that some of the compilers have not yet got all the good tricks they should be using when manipulating bool-typed expressions and also it can be one extra instruction converting values to bool strictly zero or one, not zero or any non-zero value. Here’s the D, enlarged a little so that we can see your routine in action, inlined. Your isEven boils down to two instructions with a seriously optimising compiler. I’ve included the x86-64 machine code generated by the GDC and LDC compilers so you can see how fast it is. GDC made a bit of a dog’s breakfast of my longer routine whereas LDC performed superbly. GDC generated twice as much code, but its excellent instruction scheduler and what looks like an awareness of ILP mean that the two streams of instructions will be carried out in parallel so the two streams will only take three instruction times - ie whatever the total time is for those three instruction in the one stream - not six. bool isEven( int num ) { return ! ( num & 1 ); } bool AreBothEven( int a, int b ) // returns true if both arguments are even { return isEven( a ) && isEven( b ); } === Compiler output:: GDC:: x86-64: -O3 -mcpu=native -frelease bool isEven( int ): mov eax, edi not eax and eax, 1 ret bool AreBothEven( int, int ): mov eax, edi not esi not eax and esi, 1 and eax, 1 cmovne eax, esi ret === Compiler LDC: x86-64: -O3 -mcpu=native -release bool isEven( int ): testdil, 1 seteal ret bool AreBothEven( int, int ): or edi, esi testdil, 1 seteal ret
Re: quick question, probably of little importance...
On 27/04/2023 11:07 AM, WhatMeWorry wrote: On Wednesday, 26 April 2023 at 23:02:07 UTC, Richard (Rikki) Andrew Cattermole wrote: Don't forget ``num % 2 == 0``. None should matter, pretty much all production compilers within the last 30 years should recognize all forms of this and do the right thing. Thanks. Fastest reply ever! And I believe across the world? I suppose my examples required overhead of a function call. So maybe num % 2 == 0 is fastest? Indeed, all the way from New Zealand. I wouldn't bother timing this. A compiler will rewrite it and emit whatever instructions it thinks is best for a given cpu target that you select. This is one of those things that was solved 30 years ago :)
Re: quick question, probably of little importance...
On Wed, Apr 26, 2023 at 11:07:39PM +, WhatMeWorry via Digitalmars-d-learn wrote: > On Wednesday, 26 April 2023 at 23:02:07 UTC, Richard (Rikki) Andrew > Cattermole wrote: > > Don't forget ``num % 2 == 0``. > > > > None should matter, pretty much all production compilers within the > > last 30 years should recognize all forms of this and do the right > > thing. > > Thanks. Fastest reply ever! And I believe across the world? I > suppose my examples required overhead of a function call. So maybe num > % 2 == 0 is fastest? If performance matters, you'd be using an optimizing compiler. And unless you're hiding your function implementation behind a .di, almost all optimizing compilers would inline it, so you shouldn't even be able to tell the difference. T -- Without outlines, life would be pointless.
Re: quick question, probably of little importance...
On Wednesday, 26 April 2023 at 23:02:07 UTC, Richard (Rikki) Andrew Cattermole wrote: Don't forget ``num % 2 == 0``. None should matter, pretty much all production compilers within the last 30 years should recognize all forms of this and do the right thing. Thanks. Fastest reply ever! And I believe across the world? I suppose my examples required overhead of a function call. So maybe num % 2 == 0 is fastest?
Re: quick question, probably of little importance...
Don't forget ``num % 2 == 0``. None should matter, pretty much all production compilers within the last 30 years should recognize all forms of this and do the right thing.
quick question, probably of little importance...
I just need an even/odd functionality. Don't think D has a built-in operator. // Found this C code online. int isEven(int num) { return !(num & 1); } // found this in std.functional.unaryFun alias isEven = unaryFun!("(a & 1) == 0"); assert(isEven(2) && !isEven(1)); If interested just in speed, is either one faster?
Re: (Noob question) Should subclasses be defined in separate modules?
On Friday, 13 January 2023 at 05:17:59 UTC, thebluepandabear wrote: (Sorry if this is a duplicate.) If I have the following code inside of a module: ```D class Obj { private { string name = "Hi"; } } class ObjDerived : Obj { } ``` Is it best practice to define `ObjDerived` inside another module, since `ObjDerived` can still access the members of `Obj` (since `private` is only applied to modules), or does this go against the intended use of the language? As a beginner, I am having an extremely tough time understanding why you would want to place these two classes in the same module or even have this intended behavior of `private`. I am coming from Java/Kotlin which are both strictly OO language and have different ways of encapsulation. The short answer: just think of a module as a way of grouping related objects and functions. If it makes sense to you for `ObjDerived` to have access to the internals of `Obj`, then keep them in the same module. If it doesn't, then put it somewhere else. The long answer: there's no one-size-fits all here. For a short program, a script let's say, just dump everything in one module and be done with it. For a program you're writing for your own use, do whatever you feel comfortable with, even if you plan to open source it. For something you're writing for others to use, like a library, then the first priority is to think about what the public facing API should look like. From that perspective, does `ObDerived` belong in the same module, or is it unrelated enough to go into a different one? If it does fit in the same module, then that can be enough. It is for me. I'd stop there. But some people want to go one step further and ensure that `ObjDerived` can't access the internals of `Obj`. So in that case, you can put them in two separate modules and make a `package.d` file to act as the common module name for both. I think there are good reasons to do that, but most of the time it's just a matter of preference.
(Noob question) Should subclasses be defined in separate modules?
(Sorry if this is a duplicate.) If I have the following code inside of a module: ```D class Obj { private { string name = "Hi"; } } class ObjDerived : Obj { } ``` Is it best practice to define `ObjDerived` inside another module, since `ObjDerived` can still access the members of `Obj` (since `private` is only applied to modules), or does this go against the intended use of the language? As a beginner, I am having an extremely tough time understanding why you would want to place these two classes in the same module or even have this intended behavior of `private`. I am coming from Java/Kotlin which are both strictly OO language and have different ways of encapsulation.
Re: auto scope question?
typeof(screen.output.findSplit("")) s; Perfect. That was the "essence" of my question. But thanks to Ali, I don't have to use such esoteric syntax. D is a wonderful language, but I seem to shoot myself in the foot :)
Re: auto scope question?
On 10/25/22 6:07 PM, WhatMeWorry wrote: I'm naturally getting a undefined identifier `s` error in the return. Is there some way to refactor my code? I tried to declare s outside of the else brackets like: auto screen = executeShell(cmdLine); auto s; ... { s = screen.output.findSplit("REG_SZ"); } but that doesn't compile either. string[] getPath(string cmdLine) { auto screen = executeShell(cmdLine); if (screen.status != 0) { writeln(cmdLine, " failed"); } else { writeln("screen.output = ", screen.output); auto s = screen.output.findSplit("REG_SZ"); writeln("s[0] = ", s[0]); writeln("s[1] = ", s[1]); writeln("s[2] = ", s[2]); } return (s.split(';')); // Error: undefined identifier `s` } As Ali mentioned, your logic is faulty -- you seem to write that the command failed, but then return something anyway. Also, you are returning `string[]`, so just declaring `string[] s;` should be enough. However, I did want to mention that if you do want to hoist a difficult to name type outside where it is declared with an auto, you can use `typeof`: ```d typeof(screen.output.findSplit("")) s; ``` In this case, it's just `string[]`, but the idea here is you can name a type without naming it, by using `typeof` on the expression you would have called. Hope this helps further your D knowledge ;) -Steve
Re: auto scope question?
On 10/25/22 15:07, WhatMeWorry wrote: > auto screen = executeShell(cmdLine); > auto s; That can't work because there is no information to infer the type of 's'. Judging from the return type of getPath, perhaps it's string[]: string[] s; This is the question we should answer first: What should happen when executeShell fails? a) It is an error; the program should not continue. Then we can use 'enforce' (this is my way of coding): string[] getPath(string cmdLine) { import std.exception : enforce; auto screen = executeShell(cmdLine); enforce(screen.status == 0, format!"%s failed:\n%s"(cmdLine, screen.output)); writeln("screen.output = ", screen.output); auto s = screen.output.findSplit("REG_SZ"); writeln("s[0] = ", s[0]); writeln("s[1] = ", s[1]); writeln("s[2] = ", s[2]); return (s.split(';')); } b) It is not an error; getPath() should return empty array: string[] getPath(string cmdLine) { string[] result; auto screen = executeShell(cmdLine); if (screen.status != 0) { writeln(cmdLine, " failed"); return null; // <-- HERE (null converts to any array type) } else { // ... // Now, 'return' is where 's' is defined: return (s.split(';')); } } Ali
auto scope question?
I'm naturally getting a undefined identifier `s` error in the return. Is there some way to refactor my code? I tried to declare s outside of the else brackets like: auto screen = executeShell(cmdLine); auto s; ... { s = screen.output.findSplit("REG_SZ"); } but that doesn't compile either. string[] getPath(string cmdLine) { auto screen = executeShell(cmdLine); if (screen.status != 0) { writeln(cmdLine, " failed"); } else { writeln("screen.output = ", screen.output); auto s = screen.output.findSplit("REG_SZ"); writeln("s[0] = ", s[0]); writeln("s[1] = ", s[1]); writeln("s[2] = ", s[2]); } return (s.split(';')); // Error: undefined identifier `s` }
Re: Design question regarding saving changes in the original array and/or returning a new set
On Sunday, 23 October 2022 at 17:36:25 UTC, Paul Backus wrote: On Sunday, 23 October 2022 at 13:32:44 UTC, matheus wrote: ... You say your idea is "like passing some argument", so why not actually pass an argument? For example: ... Hi, thanks for the example, and yes I'd like to do that, but I'm looking for this "chaining" things which seems to be some sort of pattern these days. Like I said to Sergey, I think I'll use the library as example, except that I think that I'd do the otherwise, calling just "sort()" would give a duplicate, and chaining with "save()", "inplace()" or whatever name is would sort in place (Caller). Thanks, Matheus.
Re: Design question regarding saving changes in the original array and/or returning a new set
On Sunday, 23 October 2022 at 16:16:55 UTC, Sergey wrote: On Sunday, 23 October 2022 at 15:47:27 UTC, matheus wrote: Hi H. S. Teoh, I think you misunderstood my question, since English is not my first language maybe this was a problem from my part, but anyway, I'm not talking about "sort" from main library. This example was if I had designed my "own version". Matheus. Hi, Matheus. I'm not an expert in programming :) But I believe it should be up to you. How you make your function... Hi, yes I know but I'd like to know what is the most "common way" of doing this. I think I'll use the library as example, except that I think that I'd do otherwise, calling "sort()" would give a duplicate, and chaining with "save()" or "inplace()" would sort the caller. Thanks, Matheus.
Re: Design question regarding saving changes in the original array and/or returning a new set
On Sunday, 23 October 2022 at 13:32:44 UTC, matheus wrote: I have a design question and I'd like to hear some advice. Let's say that I want to create a method to sort an array: arr.sort(asc); I think usually this would usually return a new set of that array but now sorted. But If I want to do this in the original, I think I would do this: arr.sort(asc).save(); The problem with this, it would create a new set and assign/copy back to the caller, which would be a waste. So I thought about this: arr.save.sort(asc); Then save would tell to "sort()" what to do beforehand, like passing some argument saying that the sort should be done direct in the caller and no copy. Is this (The latter) an approach you would use? Or there is a better way to do this. You say your idea is "like passing some argument", so why not actually pass an argument? For example: enum Direction { asc, desc } enum InPlace : bool { no, yes } ref Arr sort(ref Arr arr, Direction dir, InPlace inPlace = InPlace.no) { if (inPlace) { arr.sortInPlace(dir); return arr; } else { return arr.sortedCopy(dir); } } Usage would look like this: auto sorted = arr.sort(asc); // sorted copy arr.sort(desc, InPlace.yes); // sort in place
Re: Design question regarding saving changes in the original array and/or returning a new set
On Sunday, 23 October 2022 at 15:47:27 UTC, matheus wrote: Hi H. S. Teoh, I think you misunderstood my question, since English is not my first language maybe this was a problem from my part, but anyway, I'm not talking about "sort" from main library. This example was if I had designed my "own version". Matheus. Hi, Matheus. I'm not an expert in programming :) But I believe it should be up to you. How you make your function. If you will use "ref" in the parameter - you could operates exactly the same memory which will received in the parameter; Also there are 'in','out', 'inout' parameters that could help with management on that question.
Re: Design question regarding saving changes in the original array and/or returning a new set
Hi H. S. Teoh, I think you misunderstood my question, since English is not my first language maybe this was a problem from my part, but anyway, I'm not talking about "sort" from main library. This example was if I had designed my "own version". Matheus.
Re: Design question regarding saving changes in the original array and/or returning a new set
On Sun, Oct 23, 2022 at 01:32:44PM +, matheus via Digitalmars-d-learn wrote: > Hi, > > I have a design question and I'd like to hear some advice. Let's say > that I want to create a method to sort an array: > > arr.sort(asc); > > I think usually this would usually return a new set of that array but > now sorted. No, it does not. It sorts `arr` in-place. > But If I want to do this in the original, I think I would do this: > > arr.sort(asc).save(); That's not necessary, the .save is completely redundant. [...] > By the way in this design I'd like to have both options, return a new > set and/or change the original. If you want a new sorted array without touching the original, do this instead: auto sortedArr = arr.dup.sort(); T -- They say that "guns don't kill people, people kill people." Well I think the gun helps. If you just stood there and yelled BANG, I don't think you'd kill too many people. -- Eddie Izzard, Dressed to Kill
Design question regarding saving changes in the original array and/or returning a new set
Hi, I have a design question and I'd like to hear some advice. Let's say that I want to create a method to sort an array: arr.sort(asc); I think usually this would usually return a new set of that array but now sorted. But If I want to do this in the original, I think I would do this: arr.sort(asc).save(); The problem with this, it would create a new set and assign/copy back to the caller, which would be a waste. So I thought about this: arr.save.sort(asc); Then save would tell to "sort()" what to do beforehand, like passing some argument saying that the sort should be done direct in the caller and no copy. Is this (The latter) an approach you would use? Or there is a better way to do this. By the way in this design I'd like to have both options, return a new set and/or change the original. Thanks in advance, Matheus.
Re: Real simple question... for good programmers
On 10/22/22 5:53 PM, WhatMeWorry wrote: string[] tokens = userSID.output.split!isWhite; writeln("tokens = ", tokens); tokens = ["SID", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "S-1-5-21-3823976785-3597194045-4221507747-1779", "", "", "", "", "", "", "", ""] Is there a clever way that I can discard all the extra null strings in the resultant string array? I've been playing with isControl, whitespace, etc. Ready to rip my hair out. Try just split without the `isWhite`. If you look at the docs, you will see: "When no delimiter is provided, strings are split into an array of words, using whitespace as delimiter. Runs of whitespace are merged together (no empty words are produced)." -Steve
Re: Real simple question... for good programmers
On Saturday, 22 October 2022 at 21:53:05 UTC, WhatMeWorry wrote: string[] tokens = userSID.output.split!isWhite; writeln("tokens = ", tokens); [...] Is there a clever way that I can discard all the extra null strings in the resultant string array? Easiest way is to use [`filter`][1]. Here's an example: ```d import std.algorithm: splitter, filter; import std.uni: isWhite; // or use std.ascii for non-unicode input import std.array: array; import std.stdio: writeln; string exampleText = "Hello 123-456-ABCx\ny\tz\r\nwvu goodbye"; void main() { string[] tokens = exampleText .splitter!isWhite .filter!(t => t.length > 0) .array; writeln("tokens = ", tokens); } ``` I've also used the lazily-evaluated [`splitter`][2] instead of the eagerly-evaluated `split`, to avoid allocating a temporary array unnecessarily. [1]: https://phobos.dpldocs.info/std.algorithm.iteration.filter.html [2]: https://phobos.dpldocs.info/std.algorithm.iteration.splitter.3.html
Re: Real simple question... for good programmers
On Saturday, 22 October 2022 at 22:01:09 UTC, Enjoys Math wrote: On Saturday, 22 October 2022 at 21:53:05 UTC, WhatMeWorry wrote: string[] tokens = userSID.output.split!isWhite; writeln("tokens = ", tokens); tokens = ["SID", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "S-1-5-21-3823976785-3597194045-4221507747-1779", "", "", "", "", "", "", "", ""] Is there a clever way that I can discard all the extra null strings in the resultant string array? I've been playing with isControl, whitespace, etc. Ready to rip my hair out. Why not `strip`? Works on ranges: https://dlang.org/phobos/std_algorithm_mutation.html#.strip Strip won't work because it only works on the beginning and ends of the range. What you want is `remove`. See my other MWE post.
Re: Real simple question... for good programmers
__MWE Code:__ ``` module DlangForumsMWE; import std.stdio; import std.algorithm.mutation; int main() { //string[] tokens = userSID.output.split!isWhite; //writeln("tokens = ", tokens); auto tokens = ["SID", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "S-1-5-21-3823976785-3597194045-4221507747-1779", "", "", "", "", "", "", "", ""]; writeln("Before:\n", tokens); writeln(); tokens = tokens.remove!(x => x == ""); writeln("After:\n", tokens); readln(); return 0; } ``` __Outputs:__ ``` Before: ["SID", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "S-1-5-21-3823976785-3597194045-4221507747-1779", "", "", "", "", "", "", "", ""] After: ["SID", "S-1-5-21-3823976785-3597194045-4221507747-1779"] ```
Re: Real simple question... for good programmers
On 10/22/22 14:53, WhatMeWorry wrote: > > > string[] tokens = userSID.output.split!isWhite; > writeln("tokens = ", tokens); Could you please show minimal compilable code that demonstrates the issue. I spent some time with some guesses but failed (to get my code to compile with std.array.split). Ali P.S. Sorry for also sending email.
Re: Real simple question... for good programmers
On Saturday, 22 October 2022 at 21:53:05 UTC, WhatMeWorry wrote: string[] tokens = userSID.output.split!isWhite; writeln("tokens = ", tokens); tokens = ["SID", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "S-1-5-21-3823976785-3597194045-4221507747-1779", "", "", "", "", "", "", "", ""] Is there a clever way that I can discard all the extra null strings in the resultant string array? I've been playing with isControl, whitespace, etc. Ready to rip my hair out. Why not `strip`? Works on ranges: https://dlang.org/phobos/std_algorithm_mutation.html#.strip
Real simple question... for good programmers
string[] tokens = userSID.output.split!isWhite; writeln("tokens = ", tokens); tokens = ["SID", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "S-1-5-21-3823976785-3597194045-4221507747-1779", "", "", "", "", "", "", "", ""] Is there a clever way that I can discard all the extra null strings in the resultant string array? I've been playing with isControl, whitespace, etc. Ready to rip my hair out.
Re: probably a trivial question...
On 10/14/22 01:43, WhatMeWorry via Digitalmars-d-learn wrote: Does D provide any guidance as to what is preferred or are they identical for all intents and purposes? You won't see a difference for this specific example since the split function supports character, string and even range separators. So, use what works best for your use case. But here's the difference between them: Single quotes are for singular characters, 'hello' won't compile while ';' and '\n' (escaped newline) will. Double quotes are string literals, i.e. array of characters, which also allow escape sequences like "\r\n". Back ticks, as well as r"...", are raw or wysiwyg ("what you see is what you get") strings, they do not support escape sequences. They are super useful for regex. import std; void main() { writeln("ab\ncd"); // \n is recognized as a newline character writeln(`ab\ncd`); // `...` and r"..." are equivalent writeln(r"ab\ncd"); } will print: ab cd ab\ncd ab\ncd More info here, if you are interested: https://dlang.org/spec/lex.html#string_literals
Re: probably a trivial question...
Changing the order of lines... On 10/13/22 16:43, WhatMeWorry wrote: > return s.split(';'); // single quotes That one is a single character and very lightweigth because it's just an integral value. You can't put more than one character within single quotes: ';x' // ERROR > return s.split(";"); // double quotes That one is a string, which is the equivalent of the following "fat pointer": struct Array_ { size_t length; char * ptr; } For that reason, it can be seen as a little bit more costly. 'length' happens to be 1 but you can use multiple characters in a string: ";x" // works (Aside: There is also a '\0' character sitting next to the ';' in memory so that the literal can be passed to C functions as-is.) Double-quoted strings have the property of escaping. For example, "\n" is not 2 characters but is "the newline character". > return s.split(`;`); // back ticks They are strings as well but they don't do escaping: `\n` happens to be 2 characters. There is also strings that start with q{ and end with }: auto myString = q{ hello world }; And then there is delimited strings that use any delimiter you choose: auto myString = q"MY_DELIMITER hello world MY_DELIMITER"; Some information here: http://ddili.org/ders/d.en/literals.html#ix_literals.string%20literal Ali
probably a trivial question...
I was a little (nicely) surprised that I could use double quotes, single quotes, or back ticks in the following line of code. return s.split(";"); // double quotes or return s.split(';'); // single quotes or return s.split(`;`); // back ticks Does D provide any guidance as to what is preferred or are they identical for all intents and purposes?
Re: Question on shapes
On Tuesday, 17 May 2022 at 00:10:55 UTC, Alain De Vos wrote: Let's say a shape is ,a circle with a radius ,or a square with a rectangular size. I want to pass shapes to functions, eg to draw them on the screen, draw(myshape) or myshape.draw(); But how do i implement best shapes ? You could also do something like: ```d import std; struct Circle { double radius; void draw() { writeln(format!"Draw a circle of radius %s"(radius)); } } struct Rectangle { double width; double height; void draw() { writeln(format!"Draw a rectangle of width %s and height %s."(width,height)); } } alias Shape = SumType!(Circle,Rectangle); void main() { Shape[] shapes = [Shape(Rectangle(2.0,3.)),Shape(Circle(3.0))]; foreach(shape; shapes) { shape.match!(x=>x.draw); } } ``` or ```d import std; struct Circle { double radius; } struct Rectangle { double width; double height; } alias Shape = SumType!(Circle,Rectangle); struct Drawer { int drawerState; void drawShape(Shape shape) { shape.match!(x=>drawShape(x)); } void drawShape(Circle circle) { writeln(format!"Draw a circle of radius %s"(circle.radius)); } void drawShape(Rectangle rectangle) { writeln(format!"Draw a rectangle of width %s and height %s."(rectangle.width,rectangle.height)); } } void main() { Shape[] shapes = [Shape(Rectangle(2.0,3.)),Shape(Circle(3.0))]; Drawer d; foreach(shape; shapes) { d.drawShape(shape); } } ```
Re: Question on shapes
On Tuesday, 17 May 2022 at 09:30:12 UTC, forkit wrote: On Tuesday, 17 May 2022 at 04:37:58 UTC, Ali Çehreli wrote: In you OOP example, I am curious why you chose Shape to be an interface, rather than a base class. You can inherit from multiple interfaces, but only from one base class. So if you need multiple inheritance, better use interfaces. Especially at the first level of objects I would almost always use only interfaces, no classes. I consider this better design.
Re: Question on shapes
On 5/17/22 02:30, forkit wrote: > On Tuesday, 17 May 2022 at 04:37:58 UTC, Ali Çehreli wrote: >> > > In you OOP example, I am curious why you chose Shape to be an interface, > rather than a base class. I always have the same question. :) interface feels lighterweight, so it is an arbitrary decision for me. I haven't hit any situation where a class would be needed. One difference is, class requires the 'override' keyword in the subclasses. I really don't know any technical difference. Ali
Re: Question on shapes
On Tuesday, 17 May 2022 at 04:37:58 UTC, Ali Çehreli wrote: In you OOP example, I am curious why you chose Shape to be an interface, rather than a base class.
Re: Question on shapes
On Tuesday, 17 May 2022 at 05:08:30 UTC, matheus wrote: In D there would be a better way to do such thing? Nothing really specific to D, but for one or two properties, you might just add them as function parameters with default values: ```d void draw(float scale = 1.0f); ``` If you have a number of them (scale, color, blend state, etc.), then you might add them as members of the `Shape` class. You could then expand on that with a single draw function in the `Shape` class that handles the actual drawing, and the subclasses would then call that internally after, e.g., setting up any vertex buffers or whatever specific to the shapes. ```d class Shape { private: float scale; RGBA color; DrawBuffer buffer; // some API-specific vertex buffer or whatever protected: void drawImpl() { // get the shape on screen } public: abstract void draw(); } class Circle { override void draw() { // set up buffer ... drawImpl(); } ``` Or you could have a `DrawProperties` struct independent of the `Shape` hierarchy that you can fill out and pass to every draw call. Or set global properties in the renderer and draw objects that have the same properties all at once. There are several ways to go about it.
Re: Question on shapes
On Tuesday, 17 May 2022 at 00:10:55 UTC, Alain De Vos wrote: Let's say a shape is ,a circle with a radius ,or a square with a rectangular size. I want to pass shapes to functions, eg to draw them on the screen, draw(myshape) or myshape.draw(); But how do i implement best shapes ? In addition to all the answers, just remember that if you want to make a square class then it should inherit from the shape class and not the rectangle class. It might seem like the obvious rule is for square to inherit rectangle, since a square is a rectangle, but it's only true on the surface, not in functionality. An example is below: ```d void changeRectangle(Rectangle rectangle, int amount) { rectangle.length = rectangle.length + amount; } ... // While this works, then it's functional wrong as you must change both the length/height of a square, since they cannot differ. changeRectangle(new Square(100, 100), 50); ``` You might think that it's easy to just not call changeRectangle with a square, but what if you store the rectangles in a list, map, get it from an external data source etc. then it starts being more and more complex and for no reason at all! I know your post really isn't about such things, but I think it's a good thing to learn already.
Re: Question on shapes
On 5/16/22 22:08, matheus wrote: > interface Shape { >void draw(); >void draw(float scale); > } Interfaces can have 'final' functions: interface Shape { void draw(float scale); final void draw() { draw(1); } } Obviously, for that to work, now Circle.draw() etc. required to respond to a 'scale' parameter. > In D there would be a better way to do such thing? Reminding that class hierarchies can be deeper as well: interface A {} class B : A { void foo() {} } class C : B { override void foo() {} } Ali
Re: Question on shapes
On Tuesday, 17 May 2022 at 04:37:58 UTC, Ali Çehreli wrote: ... 2) If you want to have a shape hierarchy, then you can start by defining its interface and implement that interface by concrete shape types. Drawing is ordinarily handled by member functions: ... Hi Ali, I'm not the author but I have a question, in your second example, let's say that sometimes it would be required to "draw" with some scale factor, so (As a newbie) I would do something like this: interface Shape { void draw(); void draw(float scale); } Then in Circle class: void draw(float scale) { writeln("This circle's radius is ", radius*scale); } void draw(){ draw(1); } Then in Rectangular class: void draw(float scale) { writefln!"This rectangle's dimensions are %sx%s."(width*scale,height*scale); } void draw(){ draw(1); } So calling shape.draw() would draw with the original scale, otherwise you could call as shape.draw(some_scale); The problem is these are just 2 shapes and it could be much more, so it would required to repeat all this. In D there would be a better way to do such thing? Thanks, Matheus.
Re: Question on shapes
On 5/16/22 17:10, Alain De Vos wrote: Let's say a shape is ,a circle with a radius ,or a square with a rectangular size. I want to pass shapes to functions, eg to draw them on the screen, draw(myshape) or myshape.draw(); But how do i implement best shapes ? There are many ways of achieving this but I think you are looking for the classic object-oriented (OOP) shape hierarchy. (Option 2 below.) 1) This option does not use OOP. It uses function overloading: import std.stdio; struct Circle { float radius; } void draw(Circle circle) { writeln("This circle's radius is ", circle.radius); } struct Rectangle { float width; float height; } void draw(Rectangle rectangle) { writefln!"This rectangle's dimensions are %sx%s."(rectangle.width, rectangle.height); } void main() { draw(Circle(1.5)); draw(Rectangle(2.5, 3.5)); } That's very simple but it does not allow putting different types of shapes e.g. in the same array. 2) If you want to have a shape hierarchy, then you can start by defining its interface and implement that interface by concrete shape types. Drawing is ordinarily handled by member functions: import std.stdio; // This defines what we can do with a Shape: interface Shape { void draw(); } // This type is now a 'class' that implements Shape. class Circle : Shape { float radius; // Classes require constructors; so here is one: this (float radius) { this.radius = radius; } // No parameter needed. This function always executes on // 'this' object. void draw() { writeln("This circle's radius is ", radius); } } // Similarly, a class class Rectangle : Shape { float width; float height; this(float width, float height) { this.width = width; this.height = height; } void draw() { writefln!"This rectangle's dimensions are %sx%s."(width, height); } } // Here is the promise of polymorphism: This function takes // a Shape but the special drawing of each shape type is // handled automatically. void use(Shape shape) { shape.draw(); } void main() { // Class hierarchies allow putting different types into // the same array: Shape[] shapes; // Let's populate with alternating circles and rectangles foreach (i; 1 .. 10) { if (i % 2) { shapes ~= new Circle(i); } else { shapes ~= new Rectangle(i, i * 2); } } // And finally let's use them foreach (shape; shapes) { use(shape); } } Ali
Question on shapes
Let's say a shape is ,a circle with a radius ,or a square with a rectangular size. I want to pass shapes to functions, eg to draw them on the screen, draw(myshape) or myshape.draw(); But how do i implement best shapes ?
Re: Beginner memory question.
On Tue, Apr 19, 2022 at 05:01:15PM +, Era Scarecrow via Digitalmars-d-learn wrote: [...] > In linux using zram i've allocated and made a compressed drive of 8Gb > which took only 200k of space [...] All unallocated pages are assumed > null/zero filled, and if you zeroize a block it will unallocate the > space. Makes extracting memory bomb archives (*Terabytes of zeroized > files to fill space*) becomes rather safe in that environment. [...] Don't be too confident about the safety of extracting memory bomb archives. All the attacker has to do is to make an archive of gigantic files containing 1's instead... The repeated bytes will make it compress with very high ratio (likely the same ratio as zeroes), but when extracting, the kernel will not be able to optimize away pages filled with 1's. T -- Skill without imagination is craftsmanship and gives us many useful objects such as wickerwork picnic baskets. Imagination without skill gives us modern art. -- Tom Stoppard
Re: Beginner memory question.
On Saturday, 16 April 2022 at 20:48:15 UTC, Adam Ruppe wrote: On Saturday, 16 April 2022 at 20:41:25 UTC, WhatMeWorry wrote: Is virtual memory entering into the equation? Probably. Memory allocated doesn't physically exist until written to a lot of the time. This might be very much an OS implementation issue. In linux using zram i've allocated and made a compressed drive of 8Gb which took only 200k of space (*the data i needed to extract compresses very well and only be temporarily used*) as such saying i have said space even though i have only 4Gb of ram didn't seem to matter. All unallocated pages are assumed null/zero filled, and if you zeroize a block it will unallocate the space. Makes extracting memory bomb archives (*Terabytes of zeroized files to fill space*) becomes rather safe in that environment. I would think if it's a small space (*say 32Mb or under, or some percentage like less than 1% of available memory*) it would allocate the memory and immediately return it. If it's larger it may say it allocated a range of memory (*as long as RAM+VM could hold it*) and allocate as needed. The CPU issues page faults when you try to access unallocated memory or memory that's not in at the time and passes it to a handler; It would then allocate the page(*s*) and then resume as though it was always allocated (*alternatively suspend until it has free ram, or save the program to disk for later resuming if there's no open ports/writable-files, or just crash the program with a segment fault*). It will make some things faster, and other things slower. If it tries to allocate all memory all at once, it may fill up RAM, then swap pages out, then fill RAM up again until the said space is successful. Which could be wasteful and slow. Or maybe it will allocate/reserve necessary Swap space and then allocate as much memory as it can before returning to the process. When you run out of ram and there's tons of swapping, a fast computer can turn into a brick for several minutes for the simplest of commands, at which changing swap settings can improve things.
Re: Beginner memory question.
On Tue, Apr 19, 2022 at 12:54:06PM +, bauss via Digitalmars-d-learn wrote: > On Saturday, 16 April 2022 at 20:48:15 UTC, Adam Ruppe wrote: > > On Saturday, 16 April 2022 at 20:41:25 UTC, WhatMeWorry wrote: > > > Is virtual memory entering into the equation? > > > > Probably. Memory allocated doesn't physically exist until written to > > a lot of the time. > > You can also exceed your RAM in a lot of cases, as the OS will just > start using your disk for RAM instead, so just because you have 8 GB > of ram doesn't always mean you can only use 8 GM of RAM (in theory of > course.) In practice, having your program use more RAM than you have causes the OS to start thrashing on I/O as it scrambles to load/unload pages from the cache as your code accesses that (virtual) memory. Other programs get swapped out, everything slows down to a crawl, and your harddrive lifetime decreases by a couple of months (or maybe a year or two). So yeah, in theory definitely possible (and in fact workable as long as each individual program's entire working set can fit in RAM at the same time -- the OS can then swap out the other programs while that one program runs), but not something you want to push. Performance will slow down to an unusable crawl, and you may need a hard reboot if you don't want to spend the rest of the day waiting for the I/O thrashing to catch up with itself. Not worth it. T -- Chance favours the prepared mind. -- Louis Pasteur
Re: Beginner memory question.
On Saturday, 16 April 2022 at 20:48:15 UTC, Adam Ruppe wrote: On Saturday, 16 April 2022 at 20:41:25 UTC, WhatMeWorry wrote: Is virtual memory entering into the equation? Probably. Memory allocated doesn't physically exist until written to a lot of the time. You can also exceed your RAM in a lot of cases, as the OS will just start using your disk for RAM instead, so just because you have 8 GB of ram doesn't always mean you can only use 8 GM of RAM (in theory of course.)
Re: Beginner memory question.
On Saturday, 16 April 2022 at 20:41:25 UTC, WhatMeWorry wrote: Is virtual memory entering into the equation? Probably. Memory allocated doesn't physically exist until written to a lot of the time.
Beginner memory question.
I'm playing around with dynamic arrays and I wrote the tiny program (at bottom). I get the following output: PS C:\D\sandbox> dmd -m64 maxMem.d PS C:\D\sandbox> .\maxMem.exe Reserving 1,610,613,245 elements reserve() returned a size of: 1,610,613,245 The capacity() of big is 1,610,613,245 ulong.sizeof (num bytes) = 8 Total bytes allocated = 12,884,905,960 Total megabytes allocated = 12,288 Total gigabytes allocated = 12 The discrepancy occurs because my Windows 10 computer only has 8.0 GB of memory (and that is not even taking the OS into consideration). Are my mega and giga sizes wrong? Is virtual memory entering into the equation? import std.stdio, std.array, std.algorithm; import std.format; import core.exception; void main() { ulong[] big; // reserve returns the new capacity of the array ulong e = 1_610_613_245; // 1_610_613_246 returns out of memory error writeln("Reserving ", format("%,3d", e) ," elements"); auto u = big.reserve(e); writeln("reserve() returned a size of: ", format("%,3d", u) ); writeln("The capacity() of big is ", format("%,3d", big.capacity)); writeln("ulong.sizeof (num bytes) = ", ulong.sizeof); writeln("Total bytes allocated = ", format("%,3d", e * ulong.sizeof)); immutable ulong megabyte = 1_048_576;// (1024 x 1024) immutable ulong gigabyte = 1024 * 1024 * 1024; writeln("Total megabytes allocated = ", format("%,3d", (e * ulong.sizeof)/megabyte)); writeln("Total gigabytes allocated = ", format("%,3d", (e * ulong.sizeof)/gigabyte)); }
Re: Basic question about size_t and ulong
On Wednesday, 23 March 2022 at 00:51:42 UTC, Era Scarecrow wrote: On Tuesday, 22 March 2022 at 21:23:43 UTC, H. S. Teoh wrote: We already have this: import std.conv : to; int x; long y; y = x.to!long; // equivalent to straight assignment / cast x = y.to!int; // throws if out of range for int This particular usage can be useful, just not in the *automatic* sense i was meaning. Forgot to add this; for the more automatic mode maybe add a new tag say @autodowncast, which may add the .to!passingtype leaving said checks without needing to throw casts in a dozen places. Though i doubt Walter or Andrei would go for it.
Re: Basic question about size_t and ulong
On Tuesday, 22 March 2022 at 21:23:43 UTC, H. S. Teoh wrote: On Tue, Mar 22, 2022 at 09:11 PM, Era Scarecrow wrote: [...] I'd almost wish D had a more lenient mode and would do automatic down-casting, then complain if it *would* have failed to downcast data at runtime. [...] We already have this: import std.conv : to; int x; long y; y = x.to!long; // equivalent to straight assignment / cast x = y.to!int; // throws if out of range for int At which point I might as well just do cast(int) on everything regardless **BECAUSE** the point of it is **NOT** having to add a bunch of conversions or extra bits to it. This particular usage can be useful, just not in the *automatic* sense i was meaning.
Re: Basic question about size_t and ulong
On Tue, Mar 22, 2022 at 09:11:00PM +, Era Scarecrow via Digitalmars-d-learn wrote: [...] > I'd almost wish D had a more lenient mode and would do automatic > down-casting, then complain if it *would* have failed to downcast data > at runtime. [...] We already have this: import std.conv : to; int x; long y; y = x.to!long; // equivalent to straight assignment / cast x = y.to!int; // throws if out of range for int T -- Gone Chopin. Bach in a minuet. I see that you JS got Bach.
Re: Basic question about size_t and ulong
On Tuesday, 22 March 2022 at 18:47:19 UTC, Ali Çehreli wrote: On 3/22/22 11:28, Era Scarecrow wrote: > So when should you use size_t? I use size_t for anything that is related to count, index, etc. However, this is a contested topic because size_t is unsigned. I don't see a problem with that. It's not like you can access -300 address space or index (*although making your own index function technically you could*). I'm actually surprised signed is the default rather than unsigned. Were negative numbers really that important in 16bit MS-DOS that C had to have signed as the default? This question is probably going off topic but still be interesting to know if there's an answer. > Is it better to use int, long, size_t? D uses size_t for automatic indexes during foreach, and as I said, it makes sense to me. Otherwise, I think the go-to type should be int for small values. long, if we know it won't fit in an int. Mhmm. More or less this is what i would think. I'm just getting sick of either numbers i return that i have to feed into indexes and it complains it's too big, or putting what is going to be a smaller number in an array because the array type is too small. Casting or using masks may resolve the issue, but it may crop up again when i make a change or try to compile on a different architecture. My usual writing at this time is doing my work on a 64bit laptop, but sometimes i go and run the 32bit dmd version in windows on a different computer and checking for differences between ldc/gdc and dmd for if the code complains. I see more and more why different versions of compilers/OSes is a pain in the ass. I'd almost wish D had a more lenient mode and would do automatic down-casting, then complain if it *would* have failed to downcast data at runtime. > Or is it better to try to use the smallest type you need that > will fulfill the function's needs and just add to handle > issues due to downcasting? That may be annoying, misleading, or error-prone because smaller types are converted at least to int in expressions anyway: Yeah, and i remember reading about optimization in GCC where doing smaller types can actually be slower, much like in some architectures having offsets in memory address results in a speed penalty for non-aligned data. But yeah, if your function works on a byte, sure, it should take a byte. Expect wild disagreements on this whole topic. :) Though internally it may be an int...
Re: Basic question about size_t and ulong
On 3/22/22 11:28, Era Scarecrow wrote: > So when should you use size_t? I use size_t for anything that is related to count, index, etc. However, this is a contested topic because size_t is unsigned. As soon as you use it in an expression, the whole expression becomes unsigned as well. (Related: Usual Arithmetic Conversions at the link below.) For that reason, at least during an "ask us anything" session at a C++ conference, where Andrei was among the panel, Herb Sutter and others agreed that it was a mistake to choose unsigned for size_t. So far, I didn't have much trouble from that decision. I am always careful when subtracting two size_ts. > Is it better to use int, long, size_t? D uses size_t for automatic indexes during foreach, and as I said, it makes sense to me. Otherwise, I think the go-to type should be int for small values. long, if we know it won't fit in an int. > Or is it better to try to use the smallest type you need that will > fulfill the function's needs and just add to handle issues due to > downcasting? That may be annoying, misleading, or error-prone because smaller types are converted at least to int in expressions anyway: https://dlang.org/spec/type.html#integer-promotions (Every D programmer should know the whole section 6.4 there.) But yeah, if your function works on a byte, sure, it should take a byte. Expect wild disagreements on this whole topic. :) Ali
Re: Basic question about size_t and ulong
On Friday, 18 March 2022 at 23:01:05 UTC, Ali Çehreli wrote: P.S. On a related note, I used to make the mistake of using size_t for file offsets as well. That is a mistake because even on a 32-bit system (or build), file sizes can be larger than uint.max. So, the correct type is long for seek() so that we can seek() to an earlier place and ulong for tell(). Perhaps we should back up and ask a different question. I've been working on adaptation of Reed Solomon Codes, and i keep getting thrown with casting errors, to the point where i just want to make everything size_t to make the errors go away. So when should you use size_t? Is it better to use int, long, size_t? Or is it better to try to use the smallest type you need that will fulfill the function's needs and just add to handle issues due to downcasting?
Re: Basic question about size_t and ulong
On 3/18/22 7:01 PM, Ali Çehreli wrote: On 3/18/22 14:54, WhatMeWorry wrote: > size_t huge = uint.max; // compiles That means size_t is uint on that build. Not that Ali is wrong in the full sense, but this line alone will compile on both 64 and 32-bit systems, so it is not informative. However, the fact that assigning it to `ulong.max` doesn't work coupled with this means that it's 32-bit. You can use code like this to tell you what your platform bits are: ```d pragma(msg, cast(int)(size_t.sizeof * 8), " bit"); ``` -Steve
Re: Basic question about size_t and ulong
On 3/18/22 14:54, WhatMeWorry wrote: > size_t is an alias to one of the unsigned integral basic types, and > represents a type that is large enough to represent an offset into all > addressable memory. In practice, that general description means "size_t is either ulong or uint" depending on your platform (or build e.g. -m32 as Adam said). > size_t huge = uint.max; // compiles That means size_t is uint on that build. Ali P.S. On a related note, I used to make the mistake of using size_t for file offsets as well. That is a mistake because even on a 32-bit system (or build), file sizes can be larger than uint.max. So, the correct type is long for seek() so that we can seek() to an earlier place and ulong for tell().
Re: Basic question about size_t and ulong
On Friday, 18 March 2022 at 21:54:55 UTC, WhatMeWorry wrote: Isn't ulong an integer? And isn't memory addresses 64 bits long? Only if you are doing a 64 bit build. Try using -m64
Basic question about size_t and ulong
Quoting the D documentation: size_t is an alias to one of the unsigned integral basic types, and represents a type that is large enough to represent an offset into all addressable memory. And I have a line of code: size_t huge = ulong.max; dmd GC.d GC.d(29): Error: cannot implicitly convert expression `18446744073709551615LU` of type 'ulong` to `uint Isn't ulong an integer? And isn't memory addresses 64 bits long? size_t huge = uint.max; // compiles works but now I'm just curious. I was just seeing what is the largest dynamic array I could create.
Re: Embarrassed to ask this question because it seems so trivial but genuinely curious...
On Thu, Jan 27, 2022 at 05:42:09PM +, WhatMeWorry via Digitalmars-d-learn wrote: > While studying Ali's book at chapter "Constructor and Other Special > Functions" and the below code snippet: [...] > // Original > //this(int i) const { writeln("a const object"); } > //this(int i) immutable { writeln("an immutable object"); } > //this(int i) shared { writeln("a shared object"); } > > const this(int i) { writeln("a const object"); } > immutable this(int i) { writeln("an immutable object"); } > shared this(int i) { writeln("a shared object"); } [...] > Assuming I can speak in correct programmer-ese: I was wondering why > the qualifiers were placed after the function parameter list (int i). > Just for fun, I moved to type qualifiers before the function > definitions "this" (like a return type?) and the output was exactly > identical. So I guess my question is, is this just a matter of > esthetics or is some more nuanced goal at work here? In method declarations, modifiers like const/immutable/shared play two distinct roles: 1) Qualifying the return type of the method; 2) Qualifying the implicit `this` parameter of the method. Historically, D has been rather lax about where qualifiers in the sense of (2) can go, so that's why: const this() is the same as this() const They both mean that the implicit `this` parameter (not to be confused with `this` as the name of the ctor) is const. Personally, though, I prefer the 2nd form, because the first form could potentially be ambiguous in non-ctor member functions: struct S { const int method(); } Does the const apply to `int` or to the implicit `this` parameter? It's not obvious. Better to write it this way: int method() const; // const applied to `this` const(int) method();// const applied to return type N.B. the parentheses in `const(int)` -- while D is lax in allowing you to write `const int`, that leads to the ambiguous situation above. My personal recommendation is to always parenthesize qualified types so that they are never ambiguous. T -- Mediocrity has been pushed to extremes.
Re: Embarrassed to ask this question because it seems so trivial but genuinely curious...
On 1/27/22 12:42 PM, WhatMeWorry wrote: Assuming I can speak in correct programmer-ese: I was wondering why the qualifiers were placed after the function parameter list (int i). Just for fun, I moved to type qualifiers before the function definitions "this" (like a return type?) and the output was exactly identical. So I guess my question is, is this just a matter of esthetics or is some more nuanced goal at work here? For constructors, being on the front is not misleading. But for a member function that returns a value, take a look: ```d struct S { int * x; const int *foo() { return x; } } ``` What do you think happens here? The answer, is that this is a compiler error. The error is that the `const` applies to the `this` parameter and *not* the return value. So you are accepting a `const S`, and trying to return its member `x` as a plain `int *`. This is why we always recommend putting the `this` modifiers at the end of the function to make it visually clear that they don't apply to the return value. -Steve
Re: Embarrassed to ask this question because it seems so trivial but genuinely curious...
On Thursday, 27 January 2022 at 17:42:09 UTC, WhatMeWorry wrote: So I guess my question is, is this just a matter of esthetics or is some more nuanced goal at work here? It doesn't matter much for constructors, but in general, the problem with placing qualifiers in front is that it looks confusing: ```D struct S { immutable int[] f() { return []; } } ``` This reads as if it returns an `immutable(int[])`, but it doesn't, the `immutable` means that it can only be called on `immutable` instances of `S`.
Embarrassed to ask this question because it seems so trivial but genuinely curious...
While studying Ali's book at chapter "Constructor and Other Special Functions" and the below code snippet: import std.stdio; struct S { this(int i) { writeln("an object"); } // Original //this(int i) const { writeln("a const object"); } //this(int i) immutable { writeln("an immutable object"); } //this(int i) shared { writeln("a shared object"); } const this(int i) { writeln("a const object"); } immutable this(int i) { writeln("an immutable object"); } shared this(int i) { writeln("a shared object"); } } void main() { auto m = S(1); auto c = const(S)(2); auto i = immutable(S)(3); auto s = shared(S)(4); } Assuming I can speak in correct programmer-ese: I was wondering why the qualifiers were placed after the function parameter list (int i). Just for fun, I moved to type qualifiers before the function definitions "this" (like a return type?) and the output was exactly identical. So I guess my question is, is this just a matter of esthetics or is some more nuanced goal at work here?
Re: Linkage question
On Monday, 24 January 2022 at 19:41:30 UTC, frame wrote: On Monday, 24 January 2022 at 18:30:02 UTC, Stanislav Blinov wrote: The difference is in how arguments are being passed, which you seem to have discovered already :) Would like to know where the linkage format is defined, thx. It should be here: https://dlang.org/spec/abi.html although IIRC it might not be 100% up to date. Ah, yes. Thanks. Maybe I should read it more carefully =) It claims that the D calling convention matches C. But it seems that the arguments are pushed in order whereas C does it in reverse order and the -218697648 value is indeed my 3rd string pointer. that's a bug with dmd or the spec, arguments are currently passed in reverse order compared to C on 64-bit even though they should be the same see: https://issues.dlang.org/show_bug.cgi?id=20204 https://github.com/dlang/dmd/pull/13287 https://github.com/dlang/dlang.org/pull/3120
Re: Linkage question
On Monday, 24 January 2022 at 19:41:30 UTC, frame wrote: It claims that the D calling convention matches C. But it seems that the arguments are pushed in order whereas C does it in reverse order and the -218697648 value is indeed my 3rd string pointer. Windows has two calling conventions for C functions, `cdecl` and `stdcall`. In D, `cdecl` is called `extern (C)` and `stdcall` is called `extern (Windows)`. Windows API functions use the `stdcall` convention [1], so you need to use `extern (Windows)` when calling them from D. [1] https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
Re: Linkage question
On Monday, 24 January 2022 at 18:30:02 UTC, Stanislav Blinov wrote: The difference is in how arguments are being passed, which you seem to have discovered already :) Would like to know where the linkage format is defined, thx. It should be here: https://dlang.org/spec/abi.html although IIRC it might not be 100% up to date. Ah, yes. Thanks. Maybe I should read it more carefully =) It claims that the D calling convention matches C. But it seems that the arguments are pushed in order whereas C does it in reverse order and the -218697648 value is indeed my 3rd string pointer.
Re: Linkage question
On Monday, 24 January 2022 at 17:23:01 UTC, frame wrote: I understand that the linkage must match but besides the name mangling, what's happen here? What is the difference if I remove the `extern (C)` part from the T alias? The difference is in how arguments are being passed, which you seem to have discovered already :) Would like to know where the linkage format is defined, thx. It should be here: https://dlang.org/spec/abi.html although IIRC it might not be 100% up to date.
Linkage question
If I declare a function as extern(C) inside a DLL, I have also to cast the function pointer as extern(C) or it fails calling, eg. ```d // --- my.dll export extern (C) void log(int mode, string a, string b, string c) { /* stuff */ } // --- main.d alias T = extern (C) void function(int, string, string, string); auto fnPtr = cast(T)GetProcAddress(/* stuff */); ``` I understand that the linkage must match but besides the name mangling, what's happen here? What is the difference if I remove the `extern (C)` part from the T alias? Doing that supplies 2nd and 3rd paramter as fine pointers but the 1st argument comes wrong (eg. 10 becomes -218697648) and the last argument is garbage too, so the D-linkage format is something different. Would like to know where the linkage format is defined, thx.
Re: map question
On Sunday, 23 January 2022 at 09:38:57 UTC, Siarhei Siamashka wrote: On Sunday, 23 January 2022 at 09:08:46 UTC, Stanislav Blinov wrote: Using `iota` here incurs additional computation and argument copies that are actually never used, i.e. wasted work. So I'd say go with `generate`, as that seems the intent. Isn't this normally a compiler's job to eliminate all unused computations and copies? It is the programmer's job long before it is the compiler's. It can do wonders on your "minimal" code but it's not its job to read your mind. ```D auto foobar1(size_t n) { return n.iota.map!(_ => 123).array; } auto foobar2(size_t n) { return generate!(() => 123).take(n).array; } ``` LDC with "-O -release" command line options generates pretty much identical code for foobar1 and foobar2 (I'm only showing the main loop, but the rest is also the same): ``` 20: 48 39 c8cmp%rcx,%rax 23: 74 18 je 3d <_D2zz7foobar1FNaNbNfmZAi+0x3d> 25: c7 04 8a 7b 00 00 00movl $0x7b,(%rdx,%rcx,4) 2c: 48 83 c1 01 add$0x1,%rcx 30: 48 39 cbcmp%rcx,%rbx 33: 75 eb jne20 <_D2zz7foobar1FNaNbNfmZAi+0x20> ``` ``` 20: 48 39 c8cmp%rcx,%rax 23: 74 18 je 3d <_D2zz7foobar2FNaNbNfmZAi+0x3d> 25: c7 04 8a 7b 00 00 00movl $0x7b,(%rdx,%rcx,4) 2c: 48 83 c1 01 add$0x1,%rcx 30: 48 39 cbcmp%rcx,%rbx 33: 75 eb jne20 <_D2zz7foobar2FNaNbNfmZAi+0x20> ``` Do you have a better example to demonstrate `generate`'s superiority? Try actual work instead of returning a literal :) Like e.g. calling dice(50, 50). One thing to note though - `generate` will always eagerly call its function at least once. Which of course should also be considered in choosing the desired implementation. I.e. if your `n` comes from user and is allowed to be 0, then `generate` becomes an inferior choice.
Re: map question
On Sunday, 23 January 2022 at 09:08:46 UTC, Stanislav Blinov wrote: Using `iota` here incurs additional computation and argument copies that are actually never used, i.e. wasted work. So I'd say go with `generate`, as that seems the intent. Isn't this normally a compiler's job to eliminate all unused computations and copies? ```D auto foobar1(size_t n) { return n.iota.map!(_ => 123).array; } auto foobar2(size_t n) { return generate!(() => 123).take(n).array; } ``` LDC with "-O -release" command line options generates pretty much identical code for foobar1 and foobar2 (I'm only showing the main loop, but the rest is also the same): ``` 20: 48 39 c8cmp%rcx,%rax 23: 74 18 je 3d <_D2zz7foobar1FNaNbNfmZAi+0x3d> 25: c7 04 8a 7b 00 00 00movl $0x7b,(%rdx,%rcx,4) 2c: 48 83 c1 01 add$0x1,%rcx 30: 48 39 cbcmp%rcx,%rbx 33: 75 eb jne20 <_D2zz7foobar1FNaNbNfmZAi+0x20> ``` ``` 20: 48 39 c8cmp%rcx,%rax 23: 74 18 je 3d <_D2zz7foobar2FNaNbNfmZAi+0x3d> 25: c7 04 8a 7b 00 00 00movl $0x7b,(%rdx,%rcx,4) 2c: 48 83 c1 01 add$0x1,%rcx 30: 48 39 cbcmp%rcx,%rbx 33: 75 eb jne20 <_D2zz7foobar2FNaNbNfmZAi+0x20> ``` Do you have a better example to demonstrate `generate`'s superiority?
Re: map question
On Saturday, 22 January 2022 at 23:54:27 UTC, forkit wrote: On Saturday, 22 January 2022 at 19:55:43 UTC, Stanislav Blinov wrote: thanks for the explanation. That really helped :-) writeln( generate!(() => dice(0.6, 1.4)).take(howManyTimes) ); [1, 1, 1, 1, 0] (or after reading Ali's response - getting rid of rnd, and using _ ) writeln( howManyTimes.iota.map!(_ => dice(0.6, 1.4)) ); [1, 0, 1, 1, 1] They produce exactly the same thing, so I guess it comes down to personal choice now. Using `iota` here incurs additional computation and argument copies that are actually never used, i.e. wasted work. So I'd say go with `generate`, as that seems the intent.
Re: map question
On Saturday, 22 January 2022 at 19:55:43 UTC, Stanislav Blinov wrote: thanks for the explanation. That really helped :-) writeln( generate!(() => dice(0.6, 1.4)).take(howManyTimes) ); [1, 1, 1, 1, 0] (or after reading Ali's response - getting rid of rnd, and using _ ) writeln( howManyTimes.iota.map!(_ => dice(0.6, 1.4)) ); [1, 0, 1, 1, 1] They produce exactly the same thing, so I guess it comes down to personal choice now.
Re: map question
On 1/22/22 11:32, forkit wrote: > trying to make sense of the below: The generate() solution shown by Stanislav Blinov is suitable here. > auto rnd = Random(unpredictableSeed); Somebody else mentioned this before but none of the programs we've seen so far seemed to need a special random number generator. So, the default one, which is already randomized, would suffice. Just drop the line above. > // ok - using 'e =>' makes sense > writeln(howManyTimes.iota.map!(e => rnd.dice(0.6, > 1.4)).format!"%(%s,%)"); When there is a syntactic need for a variable but that variable is not used, the idiomatic way of naming that variable is '_': howManyTimes.iota.map!(_ => dice(0.6, 1.4)) (Note: I did not write rnd.dice.) Ali
Re: map question
On Saturday, 22 January 2022 at 19:32:07 UTC, forkit wrote: trying to make sense of the below: // --- module test; import std; void main() { auto rnd = Random(unpredictableSeed); int howManyTimes = 5; // ok - using 'e =>' makes sense writeln(howManyTimes.iota.map!(e => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); // ok - though using 'howManyTimes =>' doesn't make much sense?? writeln(howManyTimes.iota.map!(howManyTimes => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); // NOT ok - using '5 =>' - but isn't this effectively the same as above line? //writeln(howManyTimes.iota.map!(5 => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); } // --- No, it's not the same. 'Tis not really a "map question", looks more like a question about https://dlang.org/spec/expression.html#function_literals (see #10). In the second case, you're defining a lambda with single parameter named `howManyTimes`, which is not at all related to your local variable of the same name. Third case is invalid, as you're effectively trying to do this: auto func(T)(T 5) { return rnd.dice(0.6, 1.4); } Which, of course, doesn't make any sense, does it? :) Given your use case (call a function N times), I think `generate` would be more appropriate here: ```d import std.random; import std.stdio; import std.range : generate, take; void main() { auto rnd = Random(unpredictableSeed); int howManyTimes = 5; generate!(() => rnd.dice(0.6, 1.4)).take(howManyTimes).writeln; } ```
map question
trying to make sense of the below: // --- module test; import std; void main() { auto rnd = Random(unpredictableSeed); int howManyTimes = 5; // ok - using 'e =>' makes sense writeln(howManyTimes.iota.map!(e => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); // ok - though using 'howManyTimes =>' doesn't make much sense?? writeln(howManyTimes.iota.map!(howManyTimes => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); // NOT ok - using '5 =>' - but isn't this effectively the same as above line? //writeln(howManyTimes.iota.map!(5 => rnd.dice(0.6, 1.4)).format!"%(%s,%)"); } // ---
Re: -debug question
On Friday, 21 January 2022 at 02:10:34 UTC, Steven Schveighoffer wrote: thanks Steven (and Ali too).
Re: -debug question
On 1/20/22 18:07, forkit wrote: I have a line of code, that I do NOT want executed when -debug is passed in. enforce(!exists(fname), "Oop! That file already exists!"); Is this even possible? (with using -version ..) The following should do it: debug {} else { foo(); } Ali
Re: -debug question
On 1/20/22 9:07 PM, forkit wrote: I have a line of code, that I do NOT want executed when -debug is passed in. enforce(!exists(fname), "Oop! That file already exists!"); Is this even possible? (with using -version ..) `debug` is like a `version` block. ```d debug {} else { // code that runs when -debug is not present } ``` -Steve