Re: ePub/Mobi/AZW3/PDF of Phobos Runtime Library
On Tuesday, 28 June 2022 at 21:14:42 UTC, Marcone wrote: Is there any way to do this automatically like Python? https://docs.python.org/3/download.html Of course there is. But someone has to volunteer their time and effort to do it ;-)
Re: ePub/Mobi/AZW3/PDF of Phobos Runtime Library
On Tuesday, 28 June 2022 at 18:42:11 UTC, Marcone wrote: Beloved, I love programming in D. D is my favorite programming language. I'm not a professional programmer, but I love to program. I would like to learn D deeply. Most programming languages have a PDF/CHM/MOBI/ePub version of the standard library. But D still doesn't have such a portable version of the Phobos Runtime Library. I humbly ask you to make available a portable version of the Phobos library, to better disseminate the D programming language. Thank you So assuming i understand what you're asking for here, it already exists. When you download D, you get a directory named 'html'. In that directory is a file named 'index.html'. Is that what you want? (see the Documentation menu at the top of the index.html) The only problem with that, is that it downloads fonts, so you need access to the internet. It will still work fine without access, but it will default to a font that isn't particulary nice on the eyes.
Re: Can I create a package with friendly modules
On Sunday, 12 June 2022 at 05:46:17 UTC, Mike Parker wrote: I don't get it. How does this enable one module to access the private parts of another module? Isn't 'private' *always* private to the module? The idea I had, was to be able to spread a 'module' over more than one file - for the purpose of encapsulating this and that in different physical files, while *still* protecting the 'private is private to the module' concept. e.g. // main module module myMainModule [extends: mod1, mod2, mod3]; when I compile this module myMainModule, the compiler brings the extensions of this module, and treats it as a single module. similar to the concept of bringing in different modules into a package, only more fine-grained. But if D has a one-to-one mapping between a module and a file, and if private is always private to the one module, then this could never work.
Re: Can I create a package with friendly modules
On Sunday, 12 June 2022 at 05:05:46 UTC, forkit wrote: e.g. If I could something like this: // foo_1.d module foo_1 private int a; // a is private to module foo_1 // foo_2.d module foo_2 private int b; // b is private to module foo_2 // foo.d module foo[dependencies:foo_1, foo_2]; import std; writeln a; // can call foo_1.a directly even those its private to that module writeln b; // can call foo_2.b directly even those its private to that module
Can I create a package with friendly modules
Is it possible to create a package.d, consisting of (for example), two modules, where each module can access private declarations within each other. In essence, declaring 'a module level friendship', or a kind of 'extended module' if you want. I might still want to add another module to the package, that is NOT part of that friendship between those other two modules, but is otherwise related to the solution.
Re: C-like static array size inference - how?
On Wednesday, 8 June 2022 at 01:32:42 UTC, Steven Schveighoffer wrote: I like `$`. It's got a well-defined meaning, and already is somewhat magic. -Steve I agree it's magic. warray[5..$] - this is one of the best uses of syntax magic in D! I think it's what first attracted me to the language actually. A little more 'magic', and this could be possible: int[n] myArray = [1,2,3]; ( I think I like the use of 'n' more than '..' or '$' actually).
Re: C-like static array size inference - how?
On Wednesday, 8 June 2022 at 01:11:45 UTC, Mike Parker wrote: ...The author withdrew the DIP .. That's a shame. Seems like a useful language feature. I'd be using it already if it existed. I'd have gone for: int[..] arr = [1,2,3];
Re: Why are structs and classes so different?
On Sunday, 15 May 2022 at 21:33:24 UTC, Ali Çehreli wrote: I still think my answer is the real one. My implied question remains: Why does C++ have struct and class disticnction? I know they have different default access specifications but does that warrant two kinds? Here is a very interesting article that researches this subject. https://belaycpp.com/2021/09/17/history-of-c-explanation-on-why-the-keyword-class-has-no-more-reason-to-exist/
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: Why are structs and classes so different?
On Sunday, 15 May 2022 at 15:26:40 UTC, Kevin Bailey wrote: I've done some scripting in D over the years but I never dug into D until recently. I'm going through Learning D and I was reminded that structs and classes are so different. - struct methods are non-virtual while class methods are virtual - Thus, structs can't inherit, because how would you find the child's destructor given a parent pointer? - On the stack, structs by-value but classes are by-reference I'm trying to understand why it is this way. I assume that there's some benefit for designing it this way. I'm hoping that it's not simply accidental, historical or easier for the compiler writer. A virtual function call has to pass through a virtual function look-up, and thus there is (some) overhead involved. Thus, by design, structs avoid this overhead (completely). It's also (I think) another reason why D does not support multiple inheritance. Since you would need multiple virtual function tables.
Re: Why are structs and classes so different?
On Sunday, 15 May 2022 at 15:59:17 UTC, Alain De Vos wrote: Can i summarize , structs are value-objects which live on the stack. class instances are reference objects which live on the heap. the real difference, is that structs, being value types, are passed by value, and classes, being reference types, are passed by reference. this is the most important difference to be aware of. where they live in memory should be less of the programmers concern, and more an implementation issue (although some programmers will of course consider this as well). btw. where does a struct, inside a class live?
Re: Back to Basics at DConf?
On Friday, 13 May 2022 at 15:56:31 UTC, H. S. Teoh wrote: My mental image of this is Ali presenting some simple common task, then at 3/4 of the presentation there's an amazing trick that lets you write it in D in 5 times less code than in other languages, and my mind is blown and I remember why I love D so much. :-P T perhaps someone should start a D version of this: https://github.com/ruppysuppy/Daily-Coding-Problem-Solutions
Re: Back to Basics at DConf?
On Friday, 13 May 2022 at 03:31:53 UTC, Ali Çehreli wrote: On 5/12/22 18:56, forkit wrote: > So...you want to do a talk that challenges D's complexity, by getting > back to basics? I wasn't thinking about challenging complexity but it gives me ideas. I am looking for concrete topics like templates, classes, ranges, rvalues, etc. Are those interesting? Ali Perhaps those are a little too basic for your intended audience (which is?) My first objective when searching for a path towards a solution for a problem, is setting out to find valid methods to solve that problem, and then chosing the best method (based on whatever criteria is appropriate at the time). So, perhaps a talk that focuses on comparing different methods for solving common computational tasks (e.g. search and decision problems), might be more valuable to your audience.
Re: Back to Basics at DConf?
On Thursday, 12 May 2022 at 21:58:33 UTC, Ali Çehreli wrote: I am considering proposing a presentation for DConf 2022. Would a "Back to Basics" style presentation be interesting? If, so what exact topic would you like to see? For ideas, here is what CppCon 2021 had on their track: https://cppcon2021.sched.com/?searchstring=Back+to+Basics Ali So...you want to do a talk that challenges D's complexity, by getting back to basics? I'm afraid the ship has sailed :-(
Re: range result in Tuple! and how to convert into assocArray by sort?
On Tuesday, 10 May 2022 at 03:22:04 UTC, MichaelBi wrote: s is the string, and print result as following: s.array.sort!("athen how to transfer into [['A',231],['C',247],['G',240],['T',209]]? tried map!, but can only sortout key or value... tried array(), but result is not sorted then...thanks in advance. Adding tuples to an AA is easy. Sorting the output of an AA is the tricky part. // - module test; @safe: import std; void main() { uint[dchar] myAA; Tuple!(dchar, uint) myTuple; myTuple[0] = 'C'; myTuple[1] = 247; myAA[ myTuple[0] ] = myTuple[1]; myTuple[0] = 'G'; myTuple[1] = 240; myAA[ myTuple[0] ] = myTuple[1]; myTuple[0] = 'A'; myTuple[1] = 231; myAA[ myTuple[0] ] = myTuple[1]; myTuple[0] = 'T'; myTuple[1] = 209; myAA[ myTuple[0] ] = myTuple[1]; // NOTE: associative arrays do not preserve the order of the keys inserted into the array. // See: https://dlang.org/spec/hash-map.html // if we want the output of an AA to be sorted (by key).. string[] orderedKeyPairSet; foreach(ref key, ref value; myAA.byPair) orderedKeyPairSet ~= key.to!string ~ ":" ~ value.to!string; orderedKeyPairSet.sort; foreach(ref str; orderedKeyPairSet) writeln(str); /+ A:231 C:247 G:240 T:209 +/ } //
Re: Using regular expressions when reading a file
On Friday, 6 May 2022 at 07:51:01 UTC, Alexander Zhirov wrote: On Friday, 6 May 2022 at 05:40:52 UTC, forkit wrote: auto myTuple = line.split(" = "); Well, only if as a strict form :) well.. a settings file should be following a strict format. ..otherwise...anything goes... and good luck with that... regex won't help you either in that case... e.g: user =som=eu=ser (how you going to deal with this ?)
Re: Using regular expressions when reading a file
On Thursday, 5 May 2022 at 17:53:57 UTC, Alexander Zhirov wrote: I want to use a configuration file with external settings. I'm trying to use regular expressions to read the `Property = Value` settings. I would like to do it all more beautifully. Is there any way to get rid of the line break character? How much does everything look "right"? regex never looks right ;-) try something else perhaps?? // module test; import std; void main() { auto file = File("d:\\settings.conf", "r"); string[string] aa; // create an associate array of settings -> [key:value] foreach (line; file.byLine().filter!(a => !a.empty)) { auto myTuple = line.split(" = "); aa[myTuple[0].to!string] = myTuple[1].to!string; } // write out all the settings. foreach (key, value; aa.byPair) writefln("%s:%s", key, value); writeln; // write just the host value writeln(aa["host"]); } //
Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 21:55:18 UTC, H. S. Teoh wrote: On Wed, May 04, 2022 at 09:46:50PM +, forkit via Digitalmars-d-learn wrote: [...] That languages with GC typically give the programmer some control over the GC, is evidence that programmers do care (otherwise such features would not be needed). To deny a programmer the option to release the memory that was GC allocated within a particular scope, to be release immediately after that scope exits, seems kinda cruel. [...] scope ptr = GC.malloc(size); scope(exit) GC.free(ptr); ... // use ptr however you like until end of scope T that's cruel! I just want 'scope-based deallocation of GC allocated memory'. I just want to write one word for this to happen -> 'inscope'
Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 15:04:13 UTC, cc wrote: The MemUtils package offers a `ScopedPool` utility that seems interesting. It isn't well documented however so I have no idea if it actually works like I expect. I presume this would work something akin to a VM memory snapshot/rollback for the GC? It would be pretty handy for some scenarios, say a serialization library. You specify a snapshot point (add a pool to the stack?), incur all your GC allocations necessary for generating the structure of your serialized data (which go into the pool instead of the GC proper?), then you write it to disk and pop the stack, effectively rolling back to the original memory state of your program's GC. As long as you make sure not to leak anything allocated within that phase, seems like a good deal. https://code.dlang.org/packages/memutils Interesting. My idea was ... objects marked as 'inscope' would be GC allocated in a LIFO region of the heap, rather than the general GC pool. Explicately deallocating such objects at end of scope then becomes a no brainer for the GC (since 'inscope' would ensure at compile time that no pointers/aliasing outside of that scope could exist). The LIFO would also avoid the problem of fragmentation (i.e. if the objects were allocated in the general GC pool instead of a separate pool). This would give the programmer 'scope-based deallocation of GC allocated memory'.
Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 12:57:26 UTC, Ali Çehreli wrote: On 5/3/22 22:37, forkit wrote: > In any case, I disagree that caring about when memory gets deallocted > means you shouldn't be using GC. (or did I get that one wrong too??) At least I don't agree with you there. :) Yes, one should not care about how memory gets freed if one did not care how that memory was allocated. That languages with GC typically give the programmer some control over the GC, is evidence that programmers do care (otherwise such features would not be needed). To deny a programmer the option to release the memory that was GC allocated within a particular scope, to be release immediately after that scope exits, seems kinda cruel. To force a programmer to run a full GC in such a situation, is also kinda cruel. To force a programmer back to using the ancient malloc/free well.. that's even crueler.
Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 08:23:33 UTC, Mike Parker wrote: On Wednesday, 4 May 2022 at 05:37:49 UTC, forkit wrote: That's not at all what I said. You don't have to care about *when* memory is deallocated, meaning you don't have to manage it yourself. In any case, I disagree that caring about when memory gets deallocted means you shouldn't be using GC. (or did I get that one wrong too??) You can have the best of both worlds, surely (and easily). This (example from first post): void main(){ int[] i = new int[1]; import object: destroy; destroy(i); import core.memory: GC; GC.free(GC.addrOf(cast(void *)(i.ptr))); } All you're doing here is putting unnecessary pressure on the GC. Just use `malloc` and then `free` on `scope(exit)`. Or if you want to append to the array without managing the memory yourself, then use `std.container.array` instead. That's made for deterministic memory management with no GC involvement. Reverting to C style 'malloc and free' is not the solution here, since the intent is not to revert to manually managing dynamically allocated memory. Rather, the intent was to just have 'a simple form of control' over the lifetime of the dynamically allocated memory - the object being pointed to in GC memory pool. I understand that my idea may put uncessary pressure on the existing GC, but a GC (in theory) could surely handle this scenario.. If D had such a feature, I'd already be using it.
Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 05:13:04 UTC, Mike Parker wrote: On Wednesday, 4 May 2022 at 04:52:05 UTC, forkit wrote: It is certainly *not* about you not having to care anymore (about memory management). That's not at all what I said. You don't have to care about *when* memory is deallocated, meaning you don't have to manage it yourself. In any case, I disagree that caring about when memory gets deallocted means you shouldn't be using GC. (or did I get that one wrong too??) You can have the best of both worlds, surely (and easily). This (example from first post): void main(){ int[] i = new int[1]; import object: destroy; destroy(i); import core.memory: GC; GC.free(GC.addrOf(cast(void *)(i.ptr))); } could (in theory) be replaced with this: void main(){ inscope int[] i = new int[1]; // inscope means 2 things: // (1) i cannot be referenced anywhere except within this scope. // (2) i *will* be GC'd when this scope ends }
Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 02:42:44 UTC, Mike Parker wrote: On Tuesday, 3 May 2022 at 14:57:46 UTC, Alain De Vos wrote: Note, It's not i'm against GC. But my preference is to use builtin types and libraries if possible, But at the same time be able to be sure memory is given free when a variable is going out of scope. It seems not easy to combine the two with a GC which does his best effort but as he likes or not. What I described is an optional compiler optimization. The compiler is free to avoid the GC allocation for an array literal initializer if it is possible to do so. If you were to, e.g., return the array from the function, it would 100% for sure be allocated on the GC and not the stack. In practice, I don't know if any of the compilers actually do this. Anyway, if you care when memory is deallocated, then the GC isn't the right tool for the job. The point of the GC is that you don't have to care. GC is about reducing the complexity, cognitive load, and possible bugs - associated with manual memory management. It is certainly *not* about you not having to care anymore (about memory management). Why not have an option to mark an object, so that real-time garbage collection occurs on it as it exits scope?
Re: Where I download Digital Mars C Preprocessor sppn.exe?
On Saturday, 2 April 2022 at 23:40:39 UTC, Marcone wrote: ImportC is deprecated as everything in D is deprecated and abandoned. No link works, every download link is broken as no one cares. All D code is always full of bugs and needs to be corrected by the user before trying to run it, in order to realize that it wasted time. https://dlang.org/spec/importc.html ImportC is an interesting, and possibly useful feature..to a select few, but ALL will have to carry it. IMO...ImportC will be D's biggest mistake.
Re: How to remove all characters from a string, except the integers?
On Friday, 4 March 2022 at 02:10:11 UTC, Salih Dincer wrote: On Thursday, 3 March 2022 at 20:23:14 UTC, forkit wrote: On Thursday, 3 March 2022 at 19:28:36 UTC, matheus wrote: I'm a simple man who uses D with the old C mentality: [...] ```d string s, str = "4A0B1de!2C9~6"; foreach(i;str){ if(i < '0' || i > '9'){ continue; } s ~= i; } ``` [...] mmm..but we no longer live in simple times ;-) (i.e. unicode) If you look [here](https://github.com/dlang/phobos/blob/master/std/ascii.d#L315), you'll see that it's already the same logic. If it were me I would have even written like this: ```d "4A0B1de!2C9~6".filter!(c => '0' <= c && c <= '9' ).writeln; // 401296 ``` If you get this question at an interview, please remember to first ask whether it's ascii or unicode ;-) " All of the functions in std.ascii accept Unicode characters but effectively ignore them if they're not ASCII." - https://github.com/dlang/phobos/blob/master/std/ascii.d
Re: How to use ImportC?
On Thursday, 3 March 2022 at 19:05:22 UTC, Leonardo wrote: I saw the new feature called ImportC, it's cool to be able to use C code/libraries, but I'm not much experience in C and didn't understand this incomplete documentation: https://dlang.org/spec/importc.html How to use ImportC? I think you nailed it... with "incomplete".
Re: How to remove all characters from a string, except the integers?
On Thursday, 3 March 2022 at 19:28:36 UTC, matheus wrote: I'm a simple man who uses D with the old C mentality: import std.stdio; void main(){ string s, str = "4A0B1de!2C9~6"; foreach(i;str){ if(i < '0' || i > '9'){ continue; } s ~= i; } writeln("Result: ", s); } Result: 401296 Matheus. mmm..but we no longer live in simple times ;-) (i.e. unicode)
Re: initializing struct containing user defined type
On Friday, 18 February 2022 at 16:45:24 UTC, Ali Çehreli wrote: ... I think that syntax will be obviated when D will have named arguments. Ali Huh? D doesn't have named arguments, already? That's an important component for safe(r) programming. Do you know if there is a DIP for this, and if so, it's current status.
Re: split Error - no overload matches
On Monday, 14 February 2022 at 11:37:38 UTC, ag0aep6g wrote: On 14.02.22 12:14, forkit wrote: However, if I uncomment the //import std.uni : isWhite; then it will compile. I don't understand. I thought 'import std;' would be sufficient here?? "isWhite" is ambiguous. There's std.uni.isWhite and std.ascii.isWhite. `import std;` can't know which one you want. thanks. a little more help from the compiler itself would also have been appreciated ;-) e.g: Error: The call to isWhite is ambiguous between the following methods: 'std.uni.isWhite' and 'std.ascii.isWhite'
split Error - no overload matches
This code will not compile. Error: no overload matches for `split` However, if I uncomment the //import std.uni : isWhite; then it will compile. I don't understand. I thought 'import std;' would be sufficient here?? // module test; @safe: import std; void main() { //import std.uni : isWhite; // need to uncomment this for it to compile. writeln("Learning D is fun".split!isWhite); } // ---
Re: Offline D documentation/tutorial
On Sunday, 13 February 2022 at 00:43:18 UTC, Mike Parker wrote: If you’ve installed dmd via one of the supported installers (or the zip), you should already have the html files for the spec. On Windows, they’re in a subdirectory. I assume on other platforms they’re in the standard doc location for that platform. Would be nice if you could use this html *completely* offline, too. At the moment, if your're offline, you can't download the Roboto+Slab fonts that it tries to grab off the internet, from fonts.google.com, and so the pages end up with some default font that makes it look pretty awful.
Re: how to handle very large array?
On Thursday, 10 February 2022 at 01:43:54 UTC, H. S. Teoh wrote: On Thu, Feb 10, 2022 at 01:32:00AM +, MichaelBi via Digitalmars-d-learn wrote: On Wednesday, 9 February 2022 at 19:48:49 UTC, H. S. Teoh wrote: > [...] thanks, very helpful! i am using a assocArray now... Are you sure that's what you need? T https://youtu.be/yJjpXJm7x0o?t=213
Re: How to verify DMD download with GPG?
On Tuesday, 8 February 2022 at 10:17:19 UTC, Ola Fosheim Grøstad wrote: I don't use GPG often, so I probably did something wrong, and failed to get a trusted verification. I do like the idea that a hacker cannot change the signature file if gaining access to the web/file hosts, but how to verify it in secure way? I also did not find the key listed here: https://dlang.org/download.html there are two parts to this gpg output: (1) "Good signature.." - ok. you can be sure the file is correctly signed. (2) "WARNING: This key is not certified with a trusted .." - ok. You have not fully trusted the key, that's fine, and makes sense, since you just downloaded the key, and the key itself might have been tampered with .. in which case you have a good signature from a fraudulent key. On what basis would you trust the key? Think about it ;-) btw. the key is listed there - not sure what you mean.
iteration over directories is unsafe
It is not possible to do a simple iteration over directories in @safe mode. Really? I have to resort to unsafe?? // module test; @safe: // nope. no can do. import std; void main() { auto dFiles = dirEntries("", "*.{d,di}", SpanMode.depth); foreach(d; dFiles) writeln(d.name); } //
Re: ldc executable crashes with this code
On Friday, 4 February 2022 at 15:58:19 UTC, Stanislav Blinov wrote: .. ... As others have already stated, casting immutability away is something that has to be supported, e.g. to interface with const-agnostic APIs. `@safe` requires such casts to be more verbose, with good reason. I concede ;-) That the compiler knows this is @safe: cast(char[])iStr.dup; and this is not @safe: cast(char[])iStr; is sufficent.
Re: ldc executable crashes with this code
On Friday, 4 February 2022 at 10:09:22 UTC, Patrick Schluter wrote: On Thursday, 3 February 2022 at 02:01:34 UTC, forkit wrote: On Thursday, 3 February 2022 at 01:57:12 UTC, H. S. Teoh wrote: would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?" would be nice if programmers (C or D) learnt that a typecast means "shut up compiler I know what I do". You explicitly instructed the compiler to not complain. Remove the typecast and the compiler will bring an error. That's the reason why typecasts are to be avoided as much as possible.It is often a code smell. If I had wrote the code below, then I should not expect anything, whatsoever, from the compiler. () @trustMe_I_am_a_complete_idiot { char[] palindrome = cast(char[])"able was I ere I saw elba"; } ();
Re: ldc executable crashes with this code
On Friday, 4 February 2022 at 10:09:22 UTC, Patrick Schluter wrote: On Thursday, 3 February 2022 at 02:01:34 UTC, forkit wrote: On Thursday, 3 February 2022 at 01:57:12 UTC, H. S. Teoh wrote: would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?" would be nice if programmers (C or D) learnt that a typecast means "shut up compiler I know what I do". You explicitly instructed the compiler to not complain. Remove the typecast and the compiler will bring an error. That's the reason why typecasts are to be avoided as much as possible.It is often a code smell. In C, I would have no such expectation. The cast will occur whether I typed it in or not. My problem was, that I forgot the .dup For the compiler to allow me to cast from immutable to mutable (without the .dup), makes about as much sense as the compiler allowing this: int i; i = "Hello";
Re: ldc executable crashes with this code
On Thursday, 3 February 2022 at 03:25:39 UTC, H. S. Teoh wrote: On Thu, Feb 03, 2022 at 02:01:34AM +, forkit via Digitalmars-d-learn wrote: [...] would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?" Mark your function @safe, and the compiler will stop you from unsafe casts of this nature. That's part of the reason we have @safe. ;-) T so i mark all my modules as @safe, by default. I commented it out though, so I could do the cast. Then realised I didn't need the cast at all, just the .dup now it's @safe again. But @safe or not, nothing good can come from casting an immutable string to a mutable string, and the compiler really should know that ;-)
Re: ldc executable crashes with this code
On Thursday, 3 February 2022 at 01:57:12 UTC, H. S. Teoh wrote: would be nice if the compiler told me something though :-( i.e. "hey, dude, you really wanna to that?"
Re: ldc executable crashes with this code
On Thursday, 3 February 2022 at 01:39:33 UTC, forkit wrote: oops! forgot the .dup char[] palindrome = cast(char[])"able was I ere I saw elba".dup; ;-)
Re: ldc executable crashes with this code
On Wednesday, 2 February 2022 at 23:30:50 UTC, H. S. Teoh wrote: On Wed, Feb 02, 2022 at 11:21:52PM +, forkit via Digitalmars-d-learn wrote: [...] char[] palindrome = cast(char[])"able was I ere I saw elba"; String literals are immutable by default. Casting immutable to mutable is UB (Undefined Behaviour). [...] writeln(palindrome.reverse); Especially because .reverse mutates its argument. So you're attempting to overwrite immutable data here. That's probably what caused the crash: the literal is put in the read-only segment and the OS killed the program when it tried to write to data in that read-only segment. T that explains ldc perhaps (although i don't really get it. It's cast to mutable and being assigned to mutable. in any case... ldc doesn't like it, but dmd is fine with this ??
ldc executable crashes with this code
Any reason why compiling this with ldc would cause the exe to crash? Compiling with DMD (using either declaration of palindrome works just fine though) // module test; import std; void main() { char[] palindrome = cast(char[])"able was I ere I saw elba"; //char[] palindrome = ['a','b','l','e','w','a','s','I','e','r','e','I','s','a','w','e','l','b','a']; writeln(palindrome); // note: The line below causes the exe to crash when compiled with ldc // but only if using the first version of palindrome. writeln(palindrome.reverse); } // ---
Re: gdc or ldc for faster programs?
On Wednesday, 26 January 2022 at 11:25:47 UTC, Iain Buclaw wrote: Whenever I've watched talks/demos where benchmarks were the central topic, GDC has always blown LDC out the water when it comes to matters of math. .. https://dlang.org/blog/2020/05/14/lomutos-comeback/
Re: gdc or ldc for faster programs?
On Tuesday, 25 January 2022 at 20:01:18 UTC, Johan wrote: Tough to say. Of course DMD is not a serious contender, but I believe the difference between GDC and LDC is very small and really in the details, i.e. you'll have to look at assembly to find out the delta. Have you tried `--enable-cross-module-inlining` with LDC? -Johan dmd is the best though, in terms of compilation speed without optimisation. As I write/test A LOT of code, that time saved is very much appreciated ;-) I hope it remains that way.
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 22:35:29 UTC, forkit wrote: I should point out (to anyone looking at that code I posted), that it's easier, and makes more sense, to just write: writeln( ["typeA", "typeB", "typeC"].choice ); ... but my main focus here, was learning about variadic template functions.
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 22:07:43 UTC, Ali Çehreli wrote: thanks. makes it even shorter and simpler :-) // -- module test; @safe: import std; auto RandomChoice(R...)(R r) { auto rnd = MinstdRand0(unpredictableSeed); return only(r).choice(rnd); } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); writeln( RandomChoice(5, 8, 2) ); writeln( RandomChoice(1.3, 5.09, 8, 2) ); writeln( RandomChoice(100.05, 110.8, 109.54) ); //writeln( RandomChoice("typeA", 5, 100.14) ); // nope. some issue with mixing strings with numeric types writeln( RandomChoice("typeA", 5.to!string, 100.14.to!string) ); // NOTE: This registers with -profile=gc } // --
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 11:50:08 UTC, vit wrote: thanks. problem solved (providing all parameters are of the same type). // --- module test; import std; auto RandomChoice(R...)(R r) { auto rnd = MinstdRand0(unpredictableSeed); return only(r).randomSample(1, rnd).front; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); writeln( RandomChoice(5, 8, 2) ); writeln( RandomChoice(100.05, 110.8, 109.54) ); //writeln( RandomChoice("typeA", 5, 100.14) ); // nope. they all need to be of the same type. writeln( RandomChoice("typeA", 5.to!string, 100.14.to!string) ); } //--
passing a variadic parameter to randomSample
so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // --
Re: unordered output of an associated array of associated arrays
On Tuesday, 25 January 2022 at 02:12:50 UTC, H. S. Teoh wrote: That's the *easy* way out?? Try this instead: aaTable.keys.sort.each!((k) { aaTable[k].keys.sort.each!((kk) { writefln("%s:%s:%s", k, kk, aaTable[k][kk]); }); }); T surely, this is voodoo? ;-)
Re: unordered output of an associated array of associated arrays
On Tuesday, 25 January 2022 at 00:43:07 UTC, forkit wrote: oh. thanks :-) I will get that integrated into my example code, and will post again, once it's working (so others can learn too) ok.. so I took the easy way out ;-) output is now ordered: typeA:10003:[1, 1, 1, 0, 0, 0, 0, 0] typeA:10004:[1, 1, 1, 1, 0, 0, 0, 0] typeA:10005:[1, 1, 1, 1, 1, 0, 0, 0] typeB:10001:[1, 0, 0, 0, 0, 0, 0, 0] typeB:10002:[1, 1, 0, 0, 0, 0, 0, 0] typeC:10006:[1, 1, 1, 1, 1, 1, 0, 0] typeC:10007:[1, 1, 1, 1, 1, 1, 0, 0] // -- module test; import std; void main() { auto aaTable = ([ "typeB" : [ 10002 : [1, 1, 0, 0, 0, 0, 0, 0], 10001 : [1, 0, 0, 0, 0, 0, 0, 0] ], "typeC" : [ 10007 : [1, 1, 1, 1, 1, 1, 0, 0], 10006 : [1, 1, 1, 1, 1, 1, 0, 0] ], "typeA" : [ 10005 : [1, 1, 1, 1, 1, 0, 0, 0], 10003 : [1, 1, 1, 0, 0, 0, 0, 0], 10004 : [1, 1, 1, 1, 0, 0, 0, 0] ] ]); string[] orderedKeyPairSet; foreach (key, pair; aaTable.byPair) { foreach(k, p; pair.byPair) orderedKeyPairSet ~= key ~ ":" ~ k.to!string ~ ":" ~ p.to!string; } orderedKeyPairSet.sort; foreach(s; orderedKeyPairSet) writeln(s); } // ---
Re: unordered output of an associated array of associated arrays
On Tuesday, 25 January 2022 at 00:39:05 UTC, H. S. Teoh wrote: AA's are unordered containers. Do not rely on entries to appear in any specific order when you traverse an AA; it is implementation-dependent and may differ from OS to OS / platform to platform / sequence of operations performed on the AA since its initialization / phase of the moon. Any specific order that may appear in an AA is pure coincidence and may not appear again next time, or may only appear again at 11:59:59 Feb 29 under a blue moon. If you need entries in your AA in a specific order, extract them (or their keys) into an array then sort them yourself. E.g.: string[string] myAA; auto keys = myAA.keys; sort(keys); foreach (k; keys) { ... // now keys will be in the expected order } T oh. thanks :-) I will get that integrated into my example code, and will post again, once it's working (so others can learn too)
Re: unordered output of an associated array of associated arrays
On Tuesday, 25 January 2022 at 00:23:40 UTC, forkit wrote: another example: output is: typeA: 10001:[0, 0, 1, 1, 1, 1, 1, 1] 10002:[0, 0, 0, 1, 1, 1, 1, 1] typeB: 10005:[0, 0, 0, 0, 0, 0, 1, 1] 10003:[0, 0, 0, 0, 1, 1, 1, 1] 10004:[0, 0, 0, 0, 0, 1, 1, 1] // -- module test; import std; void main() { auto aaTable2 = ([ "typeA" : [ 10001 : [0, 0, 1, 1, 1, 1, 1, 1], 10002 : [0, 0, 0, 1, 1, 1, 1, 1] ], "typeB" : [ 10003 : [0, 0, 0, 0, 1, 1, 1, 1], 10004 : [0, 0, 0, 0, 0, 1, 1, 1], 10005 : [0, 0, 0, 0, 0, 0, 1, 1] ] ]); foreach (topLevelKey, topLevelValue; aaTable2.byPair) { writefln("%s:", topLevelKey); foreach(key, value; topLevelValue) { writefln("\t%s:%s", key, value); } } } //--
unordered output of an associated array of associated arrays
so I'm trying to understand why the output of the code below, is in reverse order of the declaration (and how to fix it so that it outputs in an ordered way) i.e. output is: typeA: A2:A2value A1:A1value typeB: B3:B3value B2:B2value B1:B1value // -- module test; import std; void main() { string[string][string] aaTable = ([ "typeA" : ["A1" : "A1value", "A2" : "A2value"], "typeB" : ["B1" : "B1value", "B2" : "B2value", "B3" : "B3value"] ]); foreach (topLevelKey, topLevelValue; aaTable.byPair) { writefln("%s:", topLevelKey); foreach(key, value; topLevelValue) { writefln("\t%s:%s", key, value); } } } //--
Re: dynamic format specifier possible?
On Sunday, 23 January 2022 at 22:08:28 UTC, Ali Çehreli wrote: You use an asterisk and provide the width as an argument. This one uses the length of the name of the program: import std; void main(string[] args) { int val = 999000; writefln("[%*s]", args.front.length, val); // [ 999000] } Ali perfect! thanks.
dynamic format specifier possible?
I would like to calculate the width of the format specifier dynamically, at runtime. e.g int WIDTH = something.length; then my format specifier would be: %WIDTHs instead of %9s // --- module test; import std; void main() { int val = 999000; writefln("[%9s]", val); // [ 999000] } // ---
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: How to do same as 'nmap' command from within a D program?
On Saturday, 22 January 2022 at 22:44:31 UTC, forkit wrote: and here is how to get the ip (depending on the formatting of your output of course) // --- module test; import std; void main() { auto result = execute(["bash", "-c", "nmap -sn 192.168.11.0/24 | ack -B2 \"Philips\""]); string ip; if(canFind(result.to!string, "Host is up")) { writeln("Host is up"); string str = result.to!string.chop; ip = str[ (indexOf(str, "for Philips (") + 10)..$-4 ]; writeln(ip); } else writeln("Host not found."); } //
Re: How to do same as 'nmap' command from within a D program?
On Saturday, 22 January 2022 at 23:15:18 UTC, forkit wrote: oh.. this is better i think... ip = str[ ((lastIndexOf(str, "(")) + 1) .. lastIndexOf(str, ")") ];
Re: How to do same as 'nmap' command from within a D program?
On Saturday, 22 January 2022 at 20:55:38 UTC, Daren Scot Wilson wrote: is this helpful: // --- module test; import std; void main() { auto result = execute(["bash", "-c", "nmap -sn 192.168.11.0/24 | ack -B2 \"Phillips\""]); if(canFind(result.to!string, "Host is up")) writeln("Host is up"); else writeln("Host not found."); } // ---
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: automate tuple creation
On Saturday, 22 January 2022 at 01:33:16 UTC, Steven Schveighoffer wrote: That second `valuesPerRecord` is not used in the lambda, and also it's not referring to the original element, it's the name of a parameter in the lambda. Are you sure this is doing what you want? -Steve It just worked, so i didn't think about it too much.. but it seems to work either way. And to be honest, the only part of it I understand, is the dice part ;-) In any case I changed it: from: valuesPerRecord => to: i => // void CreateDataFile(const(int) recordsNeeded, const(int) valuesPerRecord, const(string) fname) { auto rnd = Random(unpredictableSeed); auto file = File(fname, "w"); scope(exit) file.close; Appender!string bigString = appender!string; bigString.reserve(recordsNeeded); const int iotaStartNum = 100_000_001; foreach(i, id; iota(iotaStartNum, iotaStartNum + recordsNeeded).enumerate) { bigString ~= id.to!string ~ "," ~ valuesPerRecord.iota.map!(i => rnd.dice(0.6, 1.4)).format!"%(%s,%)" ~ "\n"; } file.write(bigString[]); } // ---
Re: automate tuple creation
On Saturday, 22 January 2022 at 01:33:16 UTC, Steven Schveighoffer wrote: so I why watching this video by Andrei: https://www.youtube.com/watch?v=mCrVYYlFTrA In it, he talked about writing the simplest design that could possibly work Which got me thinking // module test; @safe: import std.stdio : write, writef, writeln, writefln; import std.range : iota, enumerate; import std.array : array, byPair, Appender, appender; import std.random : Random, unpredictableSeed, dice, randomCover; import std.algorithm : map; import std.conv : to; import std.format; import std.stdio : File; import std.file : exists; import std.exception : enforce; import std.meta : Alias; debug { import std; } Random rnd; static this() { rnd = Random(unpredictableSeed); } void main(string[] args) { int recordsNeeded, valuesPerRecord; string fname; if(args.length < 4) // then set defaults { recordsNeeded = 10; valuesPerRecord= 8; version(Windows) { fname = "D:/rnd_records.txt"; } version(linux) { fname = "./rnd_records.txt"; } } else { // assumes valid values being passed in ;-) recordsNeeded = to!int(args[1]); valuesPerRecord = to!int(args[2]); fname = args[3]; } debug { writefln("%s records (where a record is: id and %s values), will be written to file: %s", recordsNeeded, valuesPerRecord, fname); } else { enforce(!exists(fname), "Oops! That file already exists!"); enforce(recordsNeeded <= 1_000_000_000, "C'mon! That's too many records!"); } CreateDataFile(recordsNeeded, valuesPerRecord, fname); writefln("All done. Check if records written to %s", fname); } void CreateDataFile(const(int) recordsNeeded, const(int) valuesPerRecord, const(string) fname) { auto file = File(fname, "w"); scope(exit) file.close; Appender!string bigString = appender!string; bigString.reserve(recordsNeeded); const int iotaStartNum = 100_000_001; foreach(i, id; iota(iotaStartNum, iotaStartNum + recordsNeeded).enumerate) { bigString ~= id.to!string ~ "," ~ valuesPerRecord.iota.map!(valuesPerRecord => cast(int)rnd.dice(0.6, 1.4)).format!"%(%s,%)" ~ "\n"; } file.write(bigString[]); } //
Re: automate tuple creation
On Friday, 21 January 2022 at 22:25:32 UTC, forkit wrote: I really like how alias and mixin can simplify my code even further: //--- int[][int][] CreateDataSet (const(int) recordsNeeded, const(int) valuesPerRecord) { int[][int][] records; records.reserve(recordsNeeded); const int iotaStartNum = 100_000_001; alias iotaValues = Alias!"iota(iotaStartNum, iotaStartNum + recordsNeeded).enumerate"; alias recordValues = Alias!"iota(valuesPerRecord).map!(valuesPerRecord => cast(int)rnd.dice(0.6, 1.4)).array"; foreach(i, id; mixin(iotaValues)) { records ~= [ id: mixin(recordValues) ]; } return records; } //---
Re: automate tuple creation
On Friday, 21 January 2022 at 21:56:33 UTC, H. S. Teoh wrote: What's the point of calling .dup here? The only reference to records is going out of scope, so why can't you just return it? The .dup is just creating extra work for nothing. T good pickup. thanks ;-) // module test; @safe: import std.stdio : write, writef, writeln, writefln; import std.range : iota, enumerate; import std.array : array, byPair, Appender, appender; import std.random : Random, unpredictableSeed, dice, randomCover; import std.algorithm : map; import std.conv : to; import std.format; import std.stdio : File; import std.file : exists; import std.exception : enforce; debug { import std; } Random rnd; static this() { rnd = Random(unpredictableSeed); } void main(string[] args) { int recordsNeeded, valuesPerRecord; string fname; if(args.length < 4) { recordsNeeded = 10; // default valuesPerRecord= 8; // default fname = "D:/rnd_records.txt"; // default //fname = "./rnd_records.txt"; // default } else { // assumes valid values being passed in ;-) recordsNeeded = to!int(args[1]); valuesPerRecord = to!int(args[2]); fname = args[3]; } debug { writefln("%s records, %s values for record, will be written to file: %s", recordsNeeded, valuesPerRecord, fname); } else { enforce(!exists(fname), "Oop! That file already exists!"); enforce(recordsNeeded <= 1_000_000_000, "C'mon! That's too many records!"); } int[][int][] records = CreateDataSet(recordsNeeded, valuesPerRecord); ProcessDataSet(records, fname); writefln("All done. Check if records written to %s", fname); } int[][int][] CreateDataSet (const(int) recordsNeeded, const(int) valuesPerRecord) { const int iotaStartNum = 100_000_001; int[][int][] records; records.reserve(recordsNeeded); debug { writefln("records.capacity is %s", records.capacity); } foreach(i, id; iota(iotaStartNum, iotaStartNum + recordsNeeded).enumerate) { // NOTE: below does register with -profile=gc records ~= [ id: iota(valuesPerRecord).map!(valuesPerRecord => cast(int)rnd.dice(0.6, 1.4)).array ]; } debug { writefln("records.length = %s", records.length); } return records; } // this creates a big string of 'formatted' records, and outputs that string to a file. void ProcessDataSet (in int[][int][] records, const(string) fname) { auto file = File(fname, "w"); scope(exit) file.close; Appender!string bigString = appender!string; bigString.reserve(records.length); debug { writefln("bigString.capacity is %s", bigString.capacity); } // NOTE: forward declaration required for this nested function void processRecord(const(int) id, const(int)[] values) { bigString ~= id.to!string ~ "," ~ values.format!"%(%s,%)" ~ "\n"; } foreach(ref const record; records) { foreach (ref rp; record.byPair) { processRecord(rp.expand); } } debug { writeln; writeln(bigString[].until("\n")); writeln; } // display just one record file.write(bigString[]); } //
Re: automate tuple creation
On Friday, 21 January 2022 at 21:43:38 UTC, forkit wrote: oops... should be: // --- int[][int][] CreateDataSet (const(int) recordsNeeded, const(int)valuesPerRecord) { int[][int][] records; records.reserve(recordsNeeded); const int iotaStartNum = 100_000_001; foreach(i, id; iota(iotaStartNum, iotaStartNum + recordsNeeded).enumerate) { records ~= [ id: iota(valuesPerRecord).map!(valuesPerRecord => cast(int)rnd.dice(0.6, 1.4)).array ]; } return records.dup; } // ---
Re: automate tuple creation
On Friday, 21 January 2022 at 21:01:11 UTC, forkit wrote: even better, I got rid of all those uncessary arrays ;-) // --- int[][int][] CreateDataSet (const(int) recordsNeeded, const(int)valuesPerRecord) { int[][int][] records; records.reserve(recordsNeeded); foreach(i, id; iota(iotaStartNum, iotaStartNum + recordsNeeded).enumerate) { records ~= [ id: iota(valuesPerRecord).map!(valuesPerRecord => cast(int)rnd.dice(0.6, 1.4)).array ]; } return records.dup; } // ---
Re: automate tuple creation
On Friday, 21 January 2022 at 18:50:46 UTC, Steven Schveighoffer wrote: Yeah, iota is a random-access range, so you can just pass it directly, and not allocate anything. Looking at the usage, it doesn't need to be an array at all. But modifying the code to properly accept the range might prove difficult for someone not used to it. -Steve thanks. that makes more sense actually ;-) now i can get rid of the idArray completely, and just do: foreach(i, id; enumerate(iota(iotaStartNum, iotaStartNum + recordsNeeded))) { records ~= [ id: valuesArray[i] ]; }
Re: automate tuple creation
On Friday, 21 January 2022 at 18:36:42 UTC, H. S. Teoh wrote: This is wasteful if you're not planning to use every ID in this million-entry long array. Much better to just use an AA to keep track of which IDs have already been generated instead. Of course, if you plan to use most of the array, then the AA may wind up using more memory than the array. So it depends on your use case. T yes, I was thinking this over as I was waking up this morning, and thought... what the hell am I doing generating all those numbers that might never get used. better to do: const int iotaStartNum = 100_000_000; int[] idArray = iota(startiotaStartNum, iotaStartNum + recordsNeeded).array;
Re: automate tuple creation
On Friday, 21 January 2022 at 09:10:56 UTC, forkit wrote: ok... in the interest of corecting the code I posted previously... ... here is a version that actually works in secs (for a million records), as opposed to hours! // --- /+ = This program create a sample dataset consisting of 'random' records, and then outputs that dataset to a file. Arguments can be passed on the command line, or otherwise default values are used instead. Example of that output can be seen at the end of this code. = +/ module test; @safe: import std.stdio : write, writef, writeln, writefln; import std.range : iota, takeExactly; import std.array : array, byPair, Appender, appender; import std.random : Random, unpredictableSeed, dice, choice, uniform; import std.algorithm : map, uniq, canFind, among; import std.conv : to; import std.format; import std.stdio : File; import std.file : exists; import std.exception : enforce; debug { import std; } Random rnd; static this() { rnd = Random(unpredictableSeed); } // thanks Ali void main(string[] args) { int recordsNeeded, valuesPerRecord; string fname; if(args.length < 4) { //recordsNeeded = 1_000_000; //recordsNeeded = 100_000; recordsNeeded = 10; valuesPerRecord= 8; //fname = "D:/rnd_records.txt"; fname = "./rnd_records.txt"; } else { // assumes valid values being passed in ;-) recordsNeeded = to!int(args[1]); valuesPerRecord = to!int(args[2]); fname = args[3]; } debug { writefln("%s records, %s values for record, will be written to file: %s", recordsNeeded, valuesPerRecord, fname); } else { enforce(!exists(fname), "Oop! That file already exists!"); } // id needs to be 9 digits, and needs to start with 999 int[] idArray = takeExactly(iota(999*10^^6, 10^^9), recordsNeeded).array; debug { writefln("idArray.length = %s", idArray.length); } int[][] valuesArray; createValuesArray(valuesArray, recordsNeeded, valuesPerRecord); int[][int][] records = CreateDataSet(idArray, valuesArray, recordsNeeded); ProcessRecords(records, fname); writefln("All done. Check if records written to %s", fname); } void createValuesArray (ref int[][] valuesArray, const(int) recordsNeeded, const(int) valuesPerRecord) { valuesArray = iota(recordsNeeded) .map!(i => iota(valuesPerRecord) .map!(valuesPerRecord => cast(int)rnd.dice(0.6, 1.4)) .array).array; // NOTE: does register with -profile=gc debug { writefln("valuesArray.length = %s", valuesArray.length); } } int[][int][] CreateDataSet (const(int)[] idArray, int[][] valuesArray, const(int) numRecords) { int[][int][] records; records.reserve(numRecords); debug { writefln("records.capacity is %s", records.capacity); } foreach(i, const id; idArray) { // NOTE: below does register with -profile=gc records ~= [ idArray[i] : valuesArray[i] ]; } debug { writefln("records.length = %s", records.length); } return records.dup; } void ProcessRecords (in int[][int][] recArray, const(string) fname) { auto file = File(fname, "w"); scope(exit) file.close; Appender!string bigString = appender!string; bigString.reserve(recArray.length); debug { writefln("bigString.capacity is %s", bigString.capacity); } // NOTE: forward declaration required for this nested function void processRecord(const(int) id, const(int)[] values) { // NOTE: below does register with -profile=gc bigString ~= id.to!string ~ "," ~ values.format!"%(%s,%)" ~ "\n"; } foreach(ref const record; recArray) { foreach (ref rp; record.byPair) { processRecord(rp.expand); } } file.write(bigString[]); } /+ sample file output: 9992511730,1,0,1,0,1,0,1 9995369731,1,1,1,1,1,1,1 9993136031,1,0,0,0,1,0,0 9998979051,1,1,1,1,0,1,1 9998438090,1,1,0,1,1,0,0 9995132750,0,0,1,0,1,1,1 9997123630,0,1,1,1,0,1,1 9998351590,1,0,0,1,1,1,1 9991454121,1,1,1,1,1,0,1 9997673520,1,1,1,1,1,1,1 +/ // ---
Re: automate tuple creation
On Friday, 21 January 2022 at 08:53:26 UTC, Stanislav Blinov wrote: turns out the problem has nothing to do with appender... It's actually this line: if (!idArray.canFind(x)): when i comment this out in the function below, the program does what I want in seconds. only problem is, the ids are no longer unique (in the file) // --- void createUniqueIDArray (ref int[] idArray, const(int) recordsNeeded) { idArray.reserve(recordsNeeded); debug { writefln("idArray.capacity is %s", idArray.capacity); } int i = 0; int x; while(i != recordsNeeded) { // id needs to be 9 digits, and needs to start with 999 x = uniform(999*10^^6, 10^^9); // thanks Stanislav // ensure every id added is unique. //if (!idArray.canFind(x)) //{ idArray ~= x; // NOTE: does NOT appear to register with -profile=gc i++; //} } debug { writefln("idArray.length = %s", idArray.length); } } //
Re: automate tuple creation
On Friday, 21 January 2022 at 04:08:33 UTC, forkit wrote: // -- void ProcessRecords (in int[][int][] recArray, const(string) fname) { auto file = File(fname, "w"); scope(exit) file.close; Appender!string bigString = appender!string; bigString.reserve(recArray.length); debug { writefln("bigString.capacity is %s", bigString.capacity); } void processRecord(const(int) id, const(int)[] values) { bigString ~= id.to!string ~ values.format!"%(%s,%)" ~ "\n"; } foreach(ref const record; recArray) { foreach (ref rp; record.byPair) { processRecord(rp.expand); } } file.write(bigString[]); } // --- actually something not right with Appender I think... 100_000 records took 20sec (ok) 1_000_000 records never finished - after 1hr/45min I cancelled the process. ??
Re: automate tuple creation
On Friday, 21 January 2022 at 03:57:01 UTC, H. S. Teoh wrote: std.array.appender is your friend. T :-) // -- void ProcessRecords (in int[][int][] recArray, const(string) fname) { auto file = File(fname, "w"); scope(exit) file.close; Appender!string bigString = appender!string; bigString.reserve(recArray.length); debug { writefln("bigString.capacity is %s", bigString.capacity); } void processRecord(const(int) id, const(int)[] values) { bigString ~= id.to!string ~ values.format!"%(%s,%)" ~ "\n"; } foreach(ref const record; recArray) { foreach (ref rp; record.byPair) { processRecord(rp.expand); } } file.write(bigString[]); } // ---
Re: automate tuple creation
On Friday, 21 January 2022 at 03:45:08 UTC, forkit wrote: On Friday, 21 January 2022 at 02:30:35 UTC, Ali Çehreli wrote: The bigger question is, why did 'formattedRecords' exist at all? You could have written the output directly to the file. Oh. this was intentional, as I wanted to write once, and only once, to the file. oops. looking back at that code, it seems I didn't write what i intended :-( I might have to use a kindof stringbuilder instead, then write a massive string once to the file. similar to C#: File.WriteAllText(Path, finalString);
Re: automate tuple creation
On Friday, 21 January 2022 at 02:30:35 UTC, Ali Çehreli wrote: The bigger question is, why did 'formattedRecords' exist at all? You could have written the output directly to the file. Oh. this was intentional, as I wanted to write once, and only once, to the file. The consequence of that decision of course, is the extra memory allocations... But in my example code I only create 10 records. In reality, my dataset will have 100,000's of records, so I don't want to write 100,000s of time to the same file. But even *worse* and with apologies, ;) here is something crazy that achieves the same thing: void ProcessRecords (in int[][int][] recArray, const(string) fname) { import std.algorithm : joiner; auto toWrite = recArray.map!(e => e.byPair); File("rnd_records.txt", "w").writefln!"%(%(%(%s,%(%s,%)%)%)\n%)"(toWrite); } I've done lot's of trial and error for the required number of nested %( %) pairs. Phew... Ali Yes, that does look worse ;-) But I'm looking into that code to see if I can salvage something from it ;-)
Re: -debug question
On Friday, 21 January 2022 at 02:10:34 UTC, Steven Schveighoffer wrote: thanks Steven (and Ali too).
-debug question
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 ..)
Re: automate tuple creation
On Friday, 21 January 2022 at 01:35:40 UTC, forkit wrote: oops. nasty mistake to make ;-) module test; @safe should be: module test; @safe:
Re: automate tuple creation
On Thursday, 20 January 2022 at 23:49:59 UTC, Ali Çehreli wrote: so here is final code, in idiomatic D, as far as I can tell ;-) curious output when using -profile=gc .. a line referring to: std.array.Appender!(immutable(char)[]).Appender.Data std.array.Appender!string.Appender.this C:\D\dmd2\windows\bin\..\..\src\phobos\std\array.d:3330 That's not real helpful, as I'm not sure what line of my code its referrring to. // --- /+ = This program create a sample dataset consisting of 'random' records, and then outputs that dataset to a file. Arguments can be passed on the command line, or otherwise default values are used instead. Example of that output can be seen at the end of this code. = +/ module test; @safe import std.stdio : write, writef, writeln, writefln; import std.range : iota; import std.array : array, byPair; import std.random : Random, unpredictableSeed, dice, choice, uniform; import std.algorithm : map, uniq, canFind; import std.conv : to; import std.stdio : File; import std.format; debug { import std; } Random rnd; static this() { rnd = Random(unpredictableSeed); } // thanks Ali void main(string[] args) { int recordsNeeded, valuesPerRecord; string fname; if(args.length < 4) { recordsNeeded = 10; valuesPerRecord= 8; fname = "D:/rnd_records.txt"; } else { // assumes valid values being passed in ;-) recordsNeeded = to!int(args[1]); valuesPerRecord = to!int(args[2]); fname = args[3]; } int[] idArray; createUniqueIDArray(idArray, recordsNeeded); int[][] valuesArray; createValuesArray(valuesArray, recordsNeeded, valuesPerRecord); int[][int][] records = CreateDataSet(idArray, valuesArray, recordsNeeded); ProcessRecords(records, fname); writefln("All done. Check if records written to %s", fname); } void createUniqueIDArray (ref int[] idArray, const(int) recordsNeeded) { idArray.reserve(recordsNeeded); debug { writefln("idArray.capacity is %s", idArray.capacity); } int i = 0; int x; while(i != recordsNeeded) { // id needs to be 9 digits, and needs to start with 999 x = uniform(999*10^^6, 10^^9); // thanks Stanislav // ensure every id added is unique. if (!idArray.canFind(x)) { idArray ~= x; // NOTE: does NOT appear to register with -profile=gc i++; } } } void createValuesArray (ref int[][] valuesArray, const(int) recordsNeeded, const(int) valuesPerRecord) { valuesArray = iota(recordsNeeded) .map!(i => iota(valuesPerRecord) .map!(valuesPerRecord => cast(int)rnd.dice(0.6, 1.4)) .array).array; // NOTE: does register with -profile=gc } int[][int][] CreateDataSet (const(int)[] idArray, int[][] valuesArray, const(int) numRecords) { int[][int][] records; records.reserve(numRecords); debug { writefln("records.capacity is %s", records.capacity); } foreach(i, const id; idArray) { // NOTE: below does register with -profile=gc records ~= [ idArray[i] : valuesArray[i] ]; } return records.dup; } void ProcessRecords (in int[][int][] recArray, const(string) fname) { auto file = File(fname, "w"); scope(exit) file.close; string[] formattedRecords; formattedRecords.reserve(recArray.length); debug { writefln("formattedRecords.capacity is %s", formattedRecords.capacity); } void processRecord(const(int) id, const(int)[] values) { // NOTE: below does register with -profile=gc formattedRecords ~= id.to!string ~ values.format!"%(%s,%)"; } foreach(ref const record; recArray) { foreach (ref rp; record.byPair) { processRecord(rp.expand); } } foreach(ref rec; formattedRecords) file.writeln(rec); } /+ sample file output: 9992511730,1,0,1,0,1,0,1 9995369731,1,1,1,1,1,1,1 9993136031,1,0,0,0,1,0,0 9998979051,1,1,1,1,0,1,1 9998438090,1,1,0,1,1,0,0 9995132750,0,0,1,0,1,1,1 9997123630,0,1,1,1,0,1,1 9998351590,1,0,0,1,1,1,1 9991454121,1,1,1,1,1,0,1 9997673520,1,1,1,1,1,1,1 +/ // ---
Re: automate tuple creation
On Thursday, 20 January 2022 at 22:31:17 UTC, Steven Schveighoffer wrote: Because it would allow altering const data. I'm not sure I understand. At what point in this function is valuesArray modified, and thus preventing it being passed in with const? // --- int[][int][] CreateDataSet ref const int[] idArray, ref int[][] valuesArray, const int numRecords) { int[][int][] records; records.reserve(numRecords); foreach(i, const id; idArray) records ~= [ idArray[i] : valuesArray[i] ]; return records.dup; } //
Re: automate tuple creation
On Thursday, 20 January 2022 at 21:16:46 UTC, forkit wrote: Cannot work out why I cannot pass valuesArray in as ref const?? get error: Error: cannot append type `const(int[])[const(int)]` to type `int[][int][]` // -- int[][int][] CreateDataSet(ref const int[] idArray, ref const(int[][]) valuesArray, const int numRecords) { int[][int][] records; records.reserve(numRecords); foreach(i, id; idArray) records ~= [ idArray[i] : valuesArray[i] ]; return records.dup; } // ---
Re: automate tuple creation
On Thursday, 20 January 2022 at 12:40:09 UTC, Stanislav Blinov wrote: Allocating 4 megs to generate 10 numbers??? You can generate a random number between 99900 and 10. ... // id needs to be 9 digits, and needs to start with 999 x = uniform(999*10^^6, 10^^9); // ensure every id added is unique. if (!result[0 .. i].canFind(x)) result[i++] = x; } import std.exception : assumeUnique; return result.assumeUnique; ... Nice. Thanks. I had to compromise a little though, as assumUnique is @system, and all my code is @safe (and trying to avoid the need for inline @system wrapper ;-) //--- void createUniqueIDArray(ref int[] idArray, int recordsNeeded) { idArray.reserve(recordsNeeded); debug { writefln("idArray.capacity is %s", idArray.capacity); } int i = 0; int x; while(i != recordsNeeded) { // generate a random 9 digit id that starts with 999 x = uniform(999*10^^6, 10^^9); // thanks Stanislav! // ensure every id added is unique. if (!idArray.canFind(x)) { idArray ~= x; // NOTE: does NOT register with -profile=gc i++; } } } //---
Re: automate tuple creation
On Thursday, 20 January 2022 at 10:11:10 UTC, bauss wrote: Don't make them random then, but use an incrementor. If you can have ids that aren't integers then you could use uuids too. https://dlang.org/phobos/std_uuid.html The 'uniqueness' of id would actually be created in the database. I just creating a dataset to simulate an export. I'm pretty much done, just wish -profile=gc was working in createUniqueIDArray(..) // --- module test; @safe: import std.stdio : write, writef, writeln, writefln; import std.range : iota, isForwardRange, hasSlicing, hasLength, isInfinite; import std.array : array, byPair; import std.random : Random, unpredictableSeed, dice, choice; import std.algorithm : map, uniq, canFind; debug { import std; } Random rnd; static this() { rnd = Random(unpredictableSeed); } void main() { const int recordsNeeded = 10; const int valuesPerRecord = 8; int[] idArray; createUniqueIDArray(idArray, recordsNeeded); int[][] valuesArray; createValuesArray(valuesArray, recordsNeeded, valuesPerRecord); int[][int][] records = CreateDataSet(idArray, valuesArray, recordsNeeded); ProcessRecords(records); } void ProcessRecords(ref const(int[][int][]) recArray) { void processRecord(ref int id, ref const(int)[] result) { writef("%s\t%s", id, result); } foreach(ref record; recArray) { foreach (ref rp; record.byPair) { processRecord(rp.expand); } writeln; } } int[][int][] CreateDataSet(ref int[] idArray, ref int[][] valuesArray, int numRecords) { int[][int][] records; records.reserve(numRecords); debug { writefln("records.capacity is %s", records.capacity); } foreach(i, id; idArray) records ~= [ idArray[i] : valuesArray[i] ]; // NOTE: does register with -profile=gc return records.dup; } void createValuesArray(ref int[][] m, size_t recordsNeeded, size_t valuesPerRecord) { m = iota(recordsNeeded) .map!(i => iota(valuesPerRecord) .map!(valuesPerRecord => cast(int)rnd.dice(0.6, 1.4)) .array).array; // NOTE: does register with -profile=gc } void createUniqueIDArray(ref int[] idArray, int recordsNeeded) { idArray.reserve(recordsNeeded); debug { writefln("idArray.capacity is %s", idArray.capacity); } // id needs to be 9 digits, and needs to start with 999 // below will contain 1_000_000 records that we can choose from. int[] ids = iota(999_000_000, 1_000_000_000).array; // NOTE: does NOT register with -profile=gc int i = 0; int x; while(i != recordsNeeded) { x = ids.choice(rnd); // ensure every id added is unique. if (!idArray.canFind(x)) { idArray ~= x; // NOTE: does NOT register with -profile=gc i++; } } } /+ sample output: 999623777 [0, 0, 1, 1, 1, 0, 0, 0] 999017078 [1, 0, 1, 1, 1, 1, 1, 1] 999269073 [1, 1, 0, 0, 1, 1, 0, 1] 999408504 [0, 1, 1, 1, 1, 1, 0, 0] 999752314 [1, 0, 0, 1, 1, 1, 1, 0] 999660730 [0, 1, 0, 0, 1, 1, 1, 1] 999709822 [1, 1, 1, 0, 1, 1, 0, 0] 999642248 [1, 1, 1, 0, 0, 1, 1, 0] 999533069 [1, 1, 1, 0, 0, 0, 0, 0] 999661591 [1, 1, 1, 1, 1, 0, 1, 1] +/ // ---
Re: automate tuple creation
On Thursday, 20 January 2022 at 04:38:39 UTC, forkit wrote: all done ;-) // --- module test; import std.stdio : writeln; import std.range : iota, isForwardRange, hasSlicing, hasLength, isInfinite; import std.array : array, Appender; import std.random : Random, unpredictableSeed, dice, choice; import std.algorithm : map, uniq, canFind; @safe: Random rnd; static this() { rnd = Random(unpredictableSeed); } void main() { int recordsNeeded = 2; int boolValuesNeeded = 3; uint[] uniqueIDs; makeUniqueIDs(uniqueIDs, recordsNeeded); uint[][] tuples; createBoolMatrix(tuples, recordsNeeded, boolValuesNeeded); uint[][uint][] records = CreateTupleDictionary(uniqueIDs, tuples); processRecords(records); } auto CreateTupleDictionary(ref uint[] ids, ref uint[][] tuples) { uint[][uint][] records; foreach(i, id; ids) records ~= [ ids[i] : tuples[i] ]; return records.dup; } void processRecords(T)(const ref T t) if (isForwardRange!T && hasSlicing!T && hasLength!T && !isInfinite!T) { t.writeln; // output from above should look like this: // [[999583661:[1, 1, 0]], [999273256:[1, 1, 1]]] // hoping to explore parallel here too... } void createBoolMatrix(ref uint[][] m, size_t numberOfTuples, size_t numberOfBoolsInTuple) { m = iota(numberOfTuples) .map!(i => iota(numberOfBoolsInTuple) .map!(numberOfBoolsInTuple => cast(uint) rnd.dice(0.6, 1.4)) .array).array; } void makeUniqueIDs(ref uint[] arr, size_t sz) { arr.reserve(sz); // id needs to be 9 digits, and needs to start with 999 int[] a = iota(999_000_000, 1_000_000_000).array; // above will contain 1_000_000 records that we can choose from. int i = 0; uint x; while(i != sz) { x = cast(uint)a.choice(rnd); // ensure every id added is unique. if (!arr.canFind(x)) { arr ~= x; i++; } } } // ---
Re: automate tuple creation
On Thursday, 20 January 2022 at 04:00:59 UTC, forkit wrote: void makeUniqueIDs(ref uint[] arr, size_t sz) { ... } arrg! what was i thinking! ;-) // --- void makeUniqueIDs(ref uint[] arr, size_t sz) { arr.reserve(sz); // id needs to be 9 digits, and needs to start with 999 int[] a = iota(999_000_000, 1_000_000_000).array; // above will contain 1_000_000 records that we can choose from. int i = 0; uint x; while(i != sz) { x = cast(uint)a.choice(rnd); // ensure every id added is unique. if (!arr.canFind(x)) { arr ~= x; i++; } else i--; } } //--
Re: automate tuple creation
On Thursday, 20 January 2022 at 00:30:44 UTC, H. S. Teoh wrote: Do the id's have to be unique? yep... I'm almost there ;-) // --- module test; import std.stdio : writeln; import std.range : iota, isForwardRange, hasSlicing, hasLength, isInfinite; import std.array : array, Appender; import std.random : Random, unpredictableSeed, dice, choice; import std.algorithm : map, uniq; @safe: Random rnd; static this() { rnd = Random(unpredictableSeed); } void main() { int recordsNeeded = 5; uint[] uniqueIDs; makeUniqueIDs(uniqueIDs, recordsNeeded); writeln(uniqueIDs); uint[][] mArrBool; // e.g: create a matrix consisting of 5 tuples, // with each tuple containing 3 random bools (0 or 1) createBoolMatrix(mArrBool,recordsNeeded, 3); // process just writeln's it's argument at the moment process(mArrBool); // [[1, 1, 1], [0, 0, 1], [1, 1, 1], [1, 1, 1], [1, 1, 0]] // to do (integrate a single value taken from uniqueIDs so that each tuple looks like this: [999575454:[1, 1, 1]] // e.g. // processRecords(records); // output from above should look like this below: // [ [999575454:[1, 1, 1]], [999704246:[0, 0, 1]], [69331:[1, 1, 1]], [999678591:[1, 1, 1]], [999691754:[1, 1, 0]] ] } void createBoolMatrix(ref uint[][] m, size_t numberOfTuples, size_t numberOfBoolsInTuple) { m = iota(numberOfTuples) .map!(i => iota(numberOfBoolsInTuple) .map!(numberOfBoolsInTuple => cast(uint) rnd.dice(0.6, 1.4)) .array).array; } void process(T)(const ref T t) if (isForwardRange!T && hasSlicing!T && hasLength!T && !isInfinite!T) { t.writeln; } void processRecords(T)(const ref T t) if (isForwardRange!T && hasSlicing!T && hasLength!T && !isInfinite!T) { t.writeln; } void makeUniqueIDs(ref uint[] arr, size_t sz) { // id needs to be 9 digits, and needs to start with 999 int[] a = iota(999_000_000, 1_000_000_000).array; // can produce a max of 1_000_000 records. Appender!(uint[]) appndr; // pre-allocate space to avoid costly reallocations appndr.reserve(sz+1); foreach(value; 1..(sz + 1)) appndr ~= cast(uint)a.choice(rnd); // just interesting to see often this asserts. //assert(appndr[].array == appndr[].uniq.array); arr = appndr[].uniq.array; // function should not return if this asserts (i.e. app will exit) assert(arr[].array == arr[].uniq.array); } // ---
Re: automate tuple creation
On Wednesday, 19 January 2022 at 21:59:15 UTC, forkit wrote: so at the moment i can get a set number of tuples, with a set number of bool values contained within each tuple. e.g. createBoolMatrix(mArrBool,3, 2); [[1, 0], [1, 1], [1, 0]] my next challenge (more for myself, but happy for input).. is to enhance this to an return an associative array: e.g createBoolAssociativeMatrix(mArrBool,3, 2); [ [1000:[1, 0]], [1001:[1, 1]], [1001:[1, 0]]] where 1000 is some random id...
Re: automate tuple creation
On Wednesday, 19 January 2022 at 22:35:58 UTC, Ali Çehreli wrote: so I combined ideas from all responses: // -- module test; import std.stdio : writeln; import std.range : iota, isForwardRange, hasSlicing, hasLength, isInfinite, array; import std.random : Random, unpredictableSeed, dice; import std.algorithm : map; @safe: Random rnd; static this() { rnd = Random(unpredictableSeed); } void main() { uint[][] mArrBool; // e.g: create a matrix consisting of 5 tuples, with each tuple containing 3 random bools (0 or 1) createBoolMatrix(mArrBool,5, 2); process(mArrBool); } void createBoolMatrix(ref uint[][] m, size_t numberOfTuples, size_t numberOfBoolsInTuple) { m = iota(numberOfTuples) .map!(i => iota(numberOfBoolsInTuple) .map!(numberOfBoolsInTuple => cast(uint) rnd.dice(0.6, 1.4)) .array).array; } void process(T)(const ref T t) if (isForwardRange!T && hasSlicing!T && hasLength!T && !isInfinite!T) { t.writeln; } //--
Re: automate tuple creation
On Wednesday, 19 January 2022 at 23:22:17 UTC, forkit wrote: oops // e.g: create a matrix consisting of 5 tuples, with each tuple containing 3 random bools (0 or 1) createBoolMatrix(mArrBool,5, 3);
Re: automate tuple creation
On Wednesday, 19 January 2022 at 21:59:15 UTC, forkit wrote: oh. that randomShuffle was unnecessary ;-)
automate tuple creation
so I have this code below, that creates an array of tuples. but instead of hardcoding 5 tuples (or hardcoding any amount of tuples), what I really want to do is automate the creation of how-ever-many tuples I ask for: i.e. instead of calling this: createBoolMatrix(mArrBool); I would call something like this: createBoolMatrix(mArrBool,5); // create an array of 5 typles. Some ideas about direction would be welcome ;-) // --- module test; import std.stdio; import std.range; import std.traits; import std.random; @safe: void main() { uint[][] mArrBool; createBoolMatrix(mArrBool); process(mArrBool); } void process(T)(const ref T t) if (isForwardRange!T && !isInfinite!T) { t.writeln; // sample output -> [[0, 1], [1, 0], [1, 1], [1, 1], [1, 1]] } void createBoolMatrix(ref uint[][] m) { auto rnd = Random(unpredictableSeed); // btw. below does register with -profile=gc m = [ [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd), [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd), [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd), [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd), [cast(uint)rnd.dice(0.6, 1.4), cast(uint)rnd.dice(0.4, 1.6)].randomShuffle(rnd) ]; } // --
Re: number ranges
On Wednesday, 19 January 2022 at 03:00:49 UTC, Tejas wrote: On Tuesday, 18 January 2022 at 20:43:08 UTC, forkit wrote: On Tuesday, 18 January 2022 at 16:02:42 UTC, Tejas wrote: Newer languages nowadays use `start..intent, think it's something we should follow? I've decided to avoid using number ranges 'directly', and instead use a wrapper function... auto range(T:T)(T a, T b) { import std.range : iota; return iota(a, (b+1)); } Aww, come on; it ain't that bad... Well that depends on entirely on what the code is doing ;-) The key is to *always* *remember* the stop index is not included. I sure hope they 'remembered' this in the code running on that telescope floating out into open space...
Re: shared defaultlib with dmd
On Tuesday, 18 January 2022 at 22:35:08 UTC, H. S. Teoh wrote: On Tue, Jan 18, 2022 at 10:04:15PM +, forkit via Digitalmars-d-learn wrote: so I use this compile command (on Windows, using ldc) -link-defaultlib-shared=true Then (in simple example) the size of my compiled .exe: From 806KB down to 18KB Oh. That's so much nicer on my SSD ;-) (yes, I understand the implictions here of dynamic sharing, but I test/compile/debug so much, that I'd like to limit the impact on my SSD drive. [...] Uhm... are you SURE this is actually nicer on your SSD? For all you know, it could be writing the 806KB first and then optimizing that in-place to reduce it to 18KB... Just because the final file size is small doesn't mean there aren't any large intermediate files. T no. there are no intermediary files. just this, and only this: (bytes) 145 EZ_Compiler_tmpfile.d 15,360 EZ_Compiler_tmpfile.exe 18,384 EZ_Compiler_tmpfile.obj
Re: shared defaultlib with dmd
On Tuesday, 18 January 2022 at 22:09:18 UTC, Adam D Ruppe wrote: On Tuesday, 18 January 2022 at 22:04:15 UTC, forkit wrote: so I use this compile command (on Windows, using ldc) On Linux dmd can do `-defaultlib=libphobos2.so` for the same thing. On Windows, dmd cannot handle a shared druntime. yes. but why? - is it technically too difficult? (ldc seems to have overcome that, if that's true)
Re: number ranges
On Tuesday, 18 January 2022 at 20:50:06 UTC, Ali Çehreli wrote: Needs a little more work to be correct. The following produces and empty range. ;) range(uint.min, uint.max) Also, is it important for the result to be the same as T? For example, even if T is ubyte, because b+1 is 'int', the range will produce ints. Ali a change of mind... never use number ranges.. not ever! ;-) (except in combination with iota)
shared defaultlib with dmd
so I use this compile command (on Windows, using ldc) -link-defaultlib-shared=true Then (in simple example) the size of my compiled .exe: From 806KB down to 18KB Oh. That's so much nicer on my SSD ;-) (yes, I understand the implictions here of dynamic sharing, but I test/compile/debug so much, that I'd like to limit the impact on my SSD drive. But I can't do this with dmd ?? it has not such option ??
Re: number ranges
On Tuesday, 18 January 2022 at 16:02:42 UTC, Tejas wrote: Newer languages nowadays use `start..intent, think it's something we should follow? I've decided to avoid using number ranges 'directly', and instead use a wrapper function... auto range(T:T)(T a, T b) { import std.range : iota; return iota(a, (b+1)); }
Re: number ranges
On Monday, 17 January 2022 at 22:28:10 UTC, H. S. Teoh wrote: If I ever needed to foreach over 1-based indices, I'd write it this way in order to avoid all confusion: foreach (i; 1 .. 5 + 1) { } This will immediately make whoever reads the code (i.e., myself after 2 months :D) wonder, "why +1?" And the answer will become clear and enlightenment ensues. ;-) T If I were able to write a compiler, my compiler would warn you: "This is ill-advised and you should know better! Please rewrite this."
Re: number ranges
On Monday, 17 January 2022 at 22:06:47 UTC, H. S. Teoh wrote: Basically, foreach (i; a .. b) is equivalent to: for (auto i = a; i < b; i++) Just think of that way and it will make sense. I think it's fair to say, that I'm familiar with 0-based indexing ;-) my concern was with the 1..5 itself. In terms of what makes sense, it actually makes more sense not to use it, at all ;-)
Re: number ranges
On Monday, 17 January 2022 at 11:58:18 UTC, Paul Backus wrote: This kind of half-open interval, which includes the lower bound but excludes the upper bound, is used in programming because it lets you write foreach (i; 0 .. array.length) writef("%s ", array[i]); ...without going past the end of the array. Yes. But the intent here is clearly stated and cannot be misunderstood -> array.length Whereas 1..5 is just an opportunity to shoot yourself in the foot. "the heretic must be cast out not because of the probability that he is wrong but because of the possibility that he is right." - Edsger W. Dijkstra
number ranges
so I'm wondering why the code below prints: 1 2 3 4 and not 1 2 3 4 5 as I would expect. foreach (value; 1..5) writef("%s ", value); also, why is this not possible: int[] arr = 1..5.array;