Is it possible to exit a contract?
Part of my code looks like this: out (result) { if (result==true) { lots of assertions... } } I would prefer an early exit like: out (result) { if (result==false) return; lots of assertions... } Is this possible somehow (return and break don't do the job...). The only thing I found is using goto, which I prefer over that gigantic if-block, but maybe there is something better, I don't know of?
Re: Is it possible to exit a contract?
On Thursday, 22 March 2018 at 16:22:04 UTC, Ali Çehreli wrote: Never thought of it before. :) I would put all that code into a function and call from the out block. I rejected this, because I've got an unease feeling using extra functions in contract programming. Can't tell, where this feeling comes from; maybe just because I've too few experience with contract programming...
enforce with return type RegexMatch!string
I've got the folling function which returns a RegexMatch!string: auto extract_list(const string entry) { // check if entry is valid return matchAll(entry, some_regex); } I call this function using enforce(extract_list(some_argument)). I think, that enforce is quite useless in this version. But I'd like to add a check, if entry is valid in the extract_list-function, something like: if (!matchFirst(entry, other_regex)) return null; That doesn't work, because I cannot cast null to RegexMatch!string (I don't understand why). What works is to create a string[] from the result of matchAll (using map and array) and use that array instead of the range. Now I can return null too. Is there a way to accomplish this?
array to string functional?
a) I've got an int[] which contains only 0 und 1. And I want to end with a string, containing 0 and 1. So [1,1,0,1,0,1] should become "110101". Of course I can do this with a loop and ~. But I think it should be doable with functional style, which is something I would like to understand better. Can anyone help me here? (I think a.map!(a=>to!char(a+'0')) does the trick, but is this good style or is there a better way?) b) After having this I'd like to split this resulting string into chunks of a fixed length, e.g. length 4, so "110101" from above should become ["1101","01"]. Again, is it possible to do that with functional style? Probably chunks from std.range might help here, but I don't get it to work. All in all, can you fill in the magic functional chain below? auto a = [1,0,1,1,1,0,1,0,1,1,1,1,0]; auto result = magic functional chain here :-) assert(result==["1011","1010","","0"]);
Re: array to string functional?
On Saturday, 15 September 2018 at 03:25:38 UTC, Paul Backus wrote: On Friday, 14 September 2018 at 20:43:45 UTC, SrMordred wrote: What you want is std.range.chunks auto a = [1,0,1,1,1,0,1,0,1,1,1,1,0]; a.map!(to!string) .join("") .chunks(4) .map!(to!string) //don´t know why the chunks are not already strings at this point ;/ .writeln; It's easier if you chunk before joining: auto a = [1,0,1,1,1,0,1,0,1,1,1,1,0]; a.map!(to!string) .chunks(4) .map!join .writeln; Oh, thanks. What I didn't know about was join. Now I wonder how I could have found out about it, without asking here? Even yet I know it's name I cannot find it, nighter in the language documentation nor in the library documentation.
Re: array to string functional?
Anotherone I'm not getting to work: From some output with newlines I want to discard all lines, that start with a # and select part of the other lines with a regex. (I know the regex r".*" is quite useless, but it will be replaced by something more usefull.) I tried the following, but non worked: output.split("\n").filter!(a=>a.length>0 && a[0]!='#').matchFirst(r".*"); output.split("\n").filter!(a=>a.length>0 && a[0]!='#').array.matchFirst(r".*"); output.split("\n").filter!(a=>a.length>0 && a[0]!='#').array.map!(matchFirst(r".*")); output.split("\n").filter!(a=>a.length>0 && a[0]!='#').array.map!(a=>matchFirst(a,r".*")); Any ideas?
Re: array to string functional?
Can you post a complete, runnable example that illustrates your problem? Strange as it is, now it works here too... - I don't know, what went wrong yesterday. Thanks anyway. :-)
Cannot use UFCS in lambda?
The following program does not compile: import std.stdio; import std.algorithm; struct A { struct S { int x; } const bool foo(in S s, in int k) { return s.xa.foo(3)).writeln; } } void main() { A().bar(); } I get (using rdmd): test.d(18): Error: no property foo for type S /usr/include/dmd/phobos/std/algorithm/iteration.d(1108): instantiated from here: >FilterResult!(__lambda1, S[]) test.d(18):instantiated from here: filter!(S[]) When I replace the UFCS-Syntax in the lambda by a function call it works: [S(1),S(2),S(3),S(4),S(5)].filter!(a=>foo(a,3)).writeln; Where is my mistake?
Re: Cannot use UFCS in lambda?
The problem is more general: you can only use top-level symbols in UFCS. You can use an identity alias template to bypass this: https://blog.thecybershadow.net/2015/04/28/the-amazing-template-that-does-nothing/ (search for UFCS in the page). Good to know. :-)
std.process.execute without capturing stderr?
I need to execute a program and capture stdout, which I hoped std.process.execute would do. But unfortunatly this command also captures stderr, which I need to be ignored. When looking at the implementation of std.process.execute I see, that I can probably do this by removing "Redirect.stderrToStdout" in the function executeImpl. But for that I have to copy lots of functions from phobos in my own code. Is there an easier way to do that? In case you wonder why I need this: I'm currently using a PHP frontend and a D backend. I'm calling the D routines with the PHP exec command which works fine, but unfortunately removes trailing whitespaces, that I need. Therefore I'd like to have a wrapper that replaces all whitespace by some escape sequences which than are restored in PHP. First I thought I can use sed for that, but unfortunately the return code gets lost here. I'm using stderr to show some progress information, which should be shown immediately. (I've you've got other ideas how to get arround this design flaw (as I see it) in php exec, I'd be happy too.) I don't want to touch the D backend - that's not the place, where the problem lies and when I decide to change the frontend I've to remember to change the backend too, which I don't like. Here my complete program: import std.process; import std.stdio; import std.array; int main(string[] args) { const result = execute(args[1..$]); writeln(result[1].replace("\\","").replace(" ","\\s")); return result[0]; }
Re: std.process.execute without capturing stderr?
On Thursday, 20 September 2018 at 07:36:06 UTC, Paul Backus wrote: Looks like `Config.stderrPassThrough` [1] should do what you want: const result = execute(args[1..$], null, Config.stdErrPassThrough); [1] https://dlang.org/phobos/std_process.html#.Config.stderrPassThrough In theory that looks good. Unfortunatley it's a relativly young feature which my compilers don't know about yet (dmd 2.079 and ldc based on an even older version of dmd). So in practice I'll probably have to wait until the next release cycle of debian in spring 2019... (maybe for the time being I'll update dmd and use dmd for this small part instead of ldc, but I yet don't know how to tell CMake to use dmd for this one file... But I'll probably figure this out.)
Re: std.process.execute without capturing stderr?
On Thursday, 20 September 2018 at 14:10:44 UTC, Steven Schveighoffer wrote: Hm... 2.079.0 had it: Sorry, I made a mistake while testing and after I found out, that it was not available in the documentation at dpldocs.info I concluded, that it must be a really new feature. But now it seems to me, that dpldocs is outdated a little bit, isn't it? Meanwhile I've got the latest version of dmd and made it working.
transposed with enforceNotJagged not throwing?
I expect this small program to throw an Exception: import std.stdio; import std.range; void main() { auto a = [[1,2], [4,5,3]]; a.transposed!(TransverseOptions.enforceNotJagged).writeln; } But it just outputs: [[1, 4], [2, 5], [3]] Is it a bug or is it me who's doing something wrong?
Re: transposed with enforceNotJagged not throwing?
On Saturday, 22 September 2018 at 12:52:45 UTC, Steven Schveighoffer wrote: It was suggested when transposed was fixed to include opIndex, but never implemented. Maybe I'm too naive, but isn't it easy to implement it just the same way, it is done with transverse? That is: putting the "static if"-part from the constructor there in the constructor of Transposed?
how to remove duplicate code in functional style
I've got the following code, which works, but obviously contains duplication. Is there a way to move that "dissection_available?...:..." to the place, where it should be? return dissection_available ?solution.dup .transposed.map!(a=>a.map!(b=>"?#."[b]).array) .zip(dissection.dup.transposed.map!(a=>a.map!(b=>"X#.?"[b]).array)) .map!(a=>a[0].to!string~" "~a[1].to!string) .join("\n") .to!string :solution.dup .transposed.map!(a=>a.map!(b=>"?#."[b]).array) .join("\n") .to!string; solution and dissection are of type const(int[][]).
2D-all?
I've got a lot of code with two-dimensional arrays, where I use stuff like: assert(matrix.all!(a=>a.all!(b=>b>=0))); Does anyone know if there is a 2D-version of all so I can write something like: assert(matrix.all2D!(a=>a>=0));
Checking if CTFE is used?
Is there a way to check if a function is indeed executed at compile time or not? (Other than going through the whole executable binaries...) I tried static this() { if (__ctfe) pragma(msg,"works"); // some other stuff } but unfortunatley this "if" is also executed at compile time, when I put it into a function that is only called at runtime. When I try "static if" instead the compiler complains about "__ctfe" being not known at compile time.
Re: Checking if CTFE is used?
On Tuesday, 18 December 2018 at 13:53:01 UTC, Stefan Koch wrote: Why would you need to know? Well, first out of curiosity. But there are also other reasons: I've got a large immutable array. Without CTFE I'd use some php script and add it as a large literal. With CTFE I don't need that php script nor do I need to put that large literal in the source code. But I need to know, that indeed the array is calculated by the compiler, else the solution with the php script would result in faster code. if(__ctfe) assert(0, "Yep, CTFE used"); That seems to work, but unfortunately, my script seems not to be evaluated at compile time... Here is a small example, similar to my code, where CTFE is not used: import std.stdio; class A { static immutable int[4] clue; static this() { if(__ctfe) assert(0, "Yep, CTFE used"); foreach (i;0..4) clue[i] = i; } } void main() { auto tmp = new A(); writeln(tmp.clue[2]); } Can you help me, finding the problem here?
Re: Checking if CTFE is used?
On Tuesday, 18 December 2018 at 14:32:29 UTC, Adam D. Ruppe wrote: CTFE is used if and only if it MUST be used by context. That's a runtime function, so no ctfe. Do something like: int[4] generate() { int[4] tmp; foreach(i; 0..4) tmp[i] = i; return tmp; } static immutable int[4] clue = generate(); Great, that worked. :-) My reasoning was, that CTFE is somewhat greedy, that is, everything that can be evaluated at compile time will be evaluated at compile time... Many thanks for your replies. :-)
Initialization of dynamic multidimensional array
With X not known at compile time: auto arr = new int[][](X,X); for (int i=0;i Is there anything better for this? I mean, the program will fill the array with zeroes, just to overwrite all of them with -1. That's wasted execution time and doesn't feel D-ish to me.
Re: Initialization of dynamic multidimensional array
On Sunday, 5 February 2017 at 21:14:33 UTC, Daniel Kozak wrote: http://stackoverflow.com/questions/24600796/d-set-default-value-for-a-struct-member-which-is-a-multidimensional-static-arr/24754361#24754361 Dne 5.2.2017 v 21:33 berni via Digitalmars-d-learn napsal(a): With X not known at compile time: auto arr = new int[][](X,X); for (int i=0;i Is there anything better for this? I mean, the program will fill the array with zeroes, just to overwrite all of them with -1. That's wasted execution time and doesn't feel D-ish to me. Thanks for the link. Looks a little bit hacky... I hoped for something more straightforward, or at least, if direct initialisation is not possible something like "arr[][] = -1;" or "arr[0..X][0..X] = -1;" But as far as I can see now, this does not exist.
Re: Initialization of dynamic multidimensional array
auto arr = uninitializedArray!(int[][])(ROWS,COLS); arr.each!"a[]=-1"; This looks like what I was looking for. At least I think I understand what's going on here. The other two suggestions are beyond my scope yet, but I'll come back, when I improved on my D skills. Thanks for your replies.
Strange behaviour of rdmd vs. dmd concerning main function
I've got two source files in two directories: Common/common.d module common; import std.stdio; int main(string[] args) { Foo foo = cast(Foo)Object.factory("special.Bar"); foo.do_something(); return 0; } abstract class Foo { abstract void do_something(); } Special/special.d module special; import std.stdio; import common; class Bar : Foo { override void do_something() { writeln("works"); } } Now I try to run it with rdmd and dmd and get quite different results: $> rdmd -ICommon Special/special.d works $> dmd -ICommon Special/special.d /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/Scrt1.o: In function `_start': (.text+0x20): undefined reference to `main' special.o:(.data.rel.ro+0x18): undefined reference to `_D6common12__ModuleInfoZ' special.o:(.data._D7special3Bar7__ClassZ+0x50): undefined reference to `_D6common3Foo7__ClassZ' collect2: error: ld returned 1 exit status Error: linker exited with status 1 I encountered this, when I was curious if I can move the main function to a diffent module, because it will be the same in several modules anyway. When testing with rdmd, everything worked. Later, I found out, that with dmd it doesn't. (And with gdc and ldc2 it doesn't work too.) For me, this looks like a bug in either rdmd or dmd. But maybe there is something about it that I do not understand.
Re: Strange behaviour of rdmd vs. dmd concerning main function
dmd only compiles in the files you actually pass to it. rdmd will try to find the required files automatically. Since you didn't pass the file with the function to dmd, it knows it exists, but leaves it out of the final link (it assumes it might come from a library or something). That's why you see the error. Ah ok, I understand. So calling with "dmd Special/special.d Common/common.d" works. But when I compile common.d to common.o (with dmd -c common.d) and remove common.d after that is there still a possibility to link? The obvious doesn't work: $> dmd Special/special.d Common/common.o Special/special.d(4): Error: module common is in file 'common.d' which cannot be read import path[0] = /usr/include/dmd/phobos import path[1] = /usr/include/dmd/druntime/import
Re: Strange behaviour of rdmd vs. dmd concerning main function
On Thursday, 9 February 2017 at 19:10:55 UTC, Daniel Kozak wrote: Dne 9.2.2017 v 17:20 berni via Digitalmars-d-learn napsal(a): [...] Ah ok, I understand. So calling with "dmd Special/special.d Common/common.d" works. But when I compile common.d to common.o (with dmd -c common.d) and remove common.d after that is there still a possibility to link? The obvious doesn't work: [...] Thats ok too, you still need to add -ICommon dmd -ICommon Special/special.d Common/common.o Doesn't work here: $> dmd -ICommon Special/special.d Common/common.o Special/special.d(4): Error: module common is in file 'common.d' which cannot be read import path[0] = Common import path[1] = /usr/include/dmd/phobos import path[2] = /usr/include/dmd/druntime/import
Re: Strange behaviour of rdmd vs. dmd concerning main function
$> dmd Special/special.d Common/common.o Special/special.d(4): Error: module common is in file 'common.d' which cannot be read import path[0] = /usr/include/dmd/phobos import path[1] = /usr/include/dmd/druntime/import This is not a linker error. It's a compiler error. You need common.d for the import, so the compiler can know which symbols are available. For any modules you import, you need either the original source file (.d) or a D interface (header) file (.di) which contains the type & function declarations and any template implementations you need. That worked. With "dmd -c -Hd=Common Common/common.d" I created a common.di file then I removed the common.d and could compile with "dmd -ICommon Special/special.d Common/common.o". With this, common.d does not need to be recompiled a lot of times if there are several special.d-files. Thank you!
Re: Initialization of dynamic multidimensional array
On Tuesday, 7 February 2017 at 19:06:22 UTC, berni wrote: auto arr = uninitializedArray!(int[][])(ROWS,COLS); arr.each!"a[]=-1"; This looks like what I was looking for. At least I think I understand what's going on here. The other two suggestions are beyond my scope yet, but I'll come back, when I improved on my D skills. Thanks for your replies. Now I tried this with a named instead of a magic constant e.g. immutable VALUE=-1; arr.each!"a[]=VALUE"; And it doesn't work anymore. I've no clue, why... Can you help me?
Re: Initialization of dynamic multidimensional array
On Friday, 10 February 2017 at 09:25:04 UTC, Daniel Kozak wrote: Now I tried this with a named instead of a magic constant e.g. immutable VALUE=-1; arr.each!"a[]=VALUE"; And it doesn't work anymore. I've no clue, why... Can you help me? Because it does not see VALUE, you need to use delegate insted of string something like this: arr.each!(a=>a[]=VALUE); Unfortunately this leeds to the same error... (Or something very simmilar.)
Re: Initialization of dynamic multidimensional array
On Friday, 10 February 2017 at 09:34:39 UTC, berni wrote: On Friday, 10 February 2017 at 09:25:04 UTC, Daniel Kozak wrote: Now I tried this with a named instead of a magic constant e.g. immutable VALUE=-1; arr.each!"a[]=VALUE"; And it doesn't work anymore. I've no clue, why... Can you help me? Because it does not see VALUE, you need to use delegate insted of string something like this: arr.each!(a=>a[]=VALUE); Unfortunately this leeds to the same error... (Or something very simmilar.) Opps, sorry. Taking back everything. It was a typo, that caused the error.
Better than "Clock.currStdTime()/10000000"
I need to measure time elapsed in seconds, like this: auto start = Clock.currStdTime(); // some stuff auto stop = Clock.currStdTime(); auto duration = (stop-start)/1000; This works, but I wonder if there is something better that using the magic constant 1000. I read about 10.secs giving the duration of 10 seconds, but I don't understand how to adapt this to my case. I've read the documentation of core.time, std.datetime (and the Introduction to this package) but I can't make head or tail of it. PS: It's not about benchmarking. I'd like to show the user the time elapsed.
A bug?
I'm not sure if this is considered a bug: import std.stdio; import std.string; int c = 0; void main() { try { write(++c," "); stdout.flush(); int[10] tmp; throw new Exception(format("%s",tmp)); } finally { main(); } } Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Segmentation fault
Re: A bug?
On Wednesday, 15 February 2017 at 16:11:36 UTC, drug wrote: No, you recursively call main() and get segfault (due to stack overflow) as expected I thought, that an stack overflow leeds to an exception. But that's not true, as I now see. Thanks for your answer.
Re: Better than "Clock.currStdTime()/10000000"
On Wednesday, 15 February 2017 at 15:58:41 UTC, Jonathan M Davis wrote: [...] MonoTime before = MonoTime.currTime; Thread.sleep(dur!"msecs"(1000)); MonoTime after = MonoTime.currTime; Duration timeElapsed = after - before; writeln(timeElapsed); } ``` I get: "1 sec, 26 μs, and 4 hnsecs" This is the correct way to do it. [...] Oh, thanks for noting this. As I finally needed the seconds as an int (or long) I had to use timeElapsed.total!"seconds" which I would not have found out without Seb's posting. :-)
how to pass stderr to core.stdc.stdio.fileno
The following code doesn't work: int no = fileno(stderr); The error message is: test.d(7): Error: function core.stdc.stdio.fileno (shared(_IO_FILE)*) is not callable using argument types (File) How can I cast stderr to something, that fileno() accepts?
Re: Strange behaviour of rdmd vs. dmd concerning main function
Something similar happend now, but this time it works with dmd and rdmd produces the error: The command that works is dmd a.d b.o where b.o is a precompiled c file, similar to https://github.com/dlang/druntime/blob/master/src/core/stdc/errno.c When using rdmd it doesn't work anymore. When I make rdmd --chatty, I can find the reason: b.o is ommited in the call of dmd. How can I make rdmd pass this parameter to dmd too?
Re: how to pass stderr to core.stdc.stdio.fileno
On Friday, 17 February 2017 at 16:08:11 UTC, Adam D. Ruppe wrote: Try fileno(core.stdc.stdio.stderr); to force it to use the C stderr object instead of the D one. Alternatively, fileno(stderr.getFP()) should do it too. http://dpldocs.info/experimental-docs/std.stdio.File.getFP.html Many thanks! That worked. And also thanks for the link. I didn't know if this docs yet. :-)
Re: how to pass stderr to core.stdc.stdio.fileno
On Friday, 17 February 2017 at 19:16:44 UTC, Adam D. Ruppe wrote: Yes, that is my documentation fork, it has a search feature if you do dpldocs.info/some_term and it tries to be easier to read and navigate, let me know how you like it! What I've seen so far, looks quite good. What I didn't understand was that large box below write in stdio. Maybe, it's because I'm not familiar with templates yet. But when I click on the question mark in the corner I get an empty search result, which, of course, doesn't explain anything.
scope with if
I wonder if it's possible to do something like this: import std.stdio; void main(string[] args) { if (args[1]=="a") { write("A"); scope (exit) write("B"); } write("C"); } I expected the output to be ACB not ABC. I understand, that the scope ends at the end of the if, but I wonder, if it's possible to have a "conditional scope" or something like this. I found a workaround using "finally", but anyway I'm curious.
Re: scope with if
Just a note - I found something, that works: import std.stdio; void main(string[] args) { immutable cond = args[1]=="a"; if (cond) write("A"); scope (exit) if (cond) write("B"); write("C"); } I'm using the immutable variable to avoid, that the condition changes later.
Re: Hello, folks! Newbie to D, have some questions!
I'm new here too (never heard of D before 2017). c). The whole community seems infused with both the Feminism/SJW I didn't tried out Rust, but that would draw me away too. (Incidentally it was a comment on alternatives for Rust, that pointed me to D.) 2. I am also curious as to what would be the best path for a complete beginner to D to learn it effectively? I started with the online version of the book of Ali Çehreli but after a while I decided to buy it and was impressed on its size (more than 700 pages!). Meanwhile I'm halfway through. At the same time I'm working on a project of mine, which I just started writing in C++ last december, because I couldn't find a better language and thought I had to bite the bullet. Meanwhile it's completely rewritten in D (but two lines of C code that I need to use a C-libraray). Whenever I came across a new concept in the book I tried to refactor that project using this concept. This approach worked very well for me. (And I appreciate this Learn-forum, because else I'd not dare to ask my seemingly silly questions.) You wrote: ... area thoroughly!The introspection ... I just realised, how much I'm thinking in D allready when I saw this: At first glance I wondered, what this thoroughly-template is about... ;-)
segmentation fault with Object.factory()
I get a segmentation fault, when I run this program: void main() { A bar = cast(A)Object.factory("AA"); bar.foo(); } class A{ abstract void foo(); } class AA:A { override void foo() {} } The call of bar.foo() is, where the segmentation fault occurs. When I use A bar = new AA(); instead of the factory it works. What's wrong here?
Re: segmentation fault with Object.factory()
On Sunday, 19 February 2017 at 10:15:49 UTC, rikki cattermole wrote: What's wrong here? void main() { A bar = cast(A)Object.factory(__MODULE__ ~ ".AA"); bar.foo(); } Oops. I overdid when trying to create a small example. With the module it works, but my original program had the module and still produced an segmentation fault. After some more investigations I found out, that it was not due to a mistake in the program, but because rdmd didn't recompile after I called it with an --extra-file added. Looks like a bug in rdmd... Here is a small example: test.d: module test; import std.stdio; void main() { B tmp = cast(B)Object.factory("test2.BB"); tmp.m1(); } interface A { abstract void m1(); } interface B:A { abstract void m2(); } class AA:A{ override void m1() { writeln("A"); } } test2.d: module test2; import std.stdio; import test; class BB:AA,B { override void m2() { writeln("B"); } } And here is what I get when compiling: $> rdmd test.d segmentation fault $> rdmd --extra-file=test2.d test.d segmentation fault $> rm -rf /tmp/.rdmd-1000/ $> rdmd --extra-file=test2.d test.d A $> rdmd -version rdmd build 20170122 [...] Should I report this bug anywhere (or am I wrong again?)
Force inline
Is it possible to force a function to be inlined? Comparing a C++ and a D program, the main difference in speed (about 20-30%) is, because I manage to force g++ to inline a function while I do not find any means to do the same on D.
Re: Force inline
On Sunday, 19 February 2017 at 20:00:00 UTC, Daniel Kozak wrote: Dne 19.2.2017 v 20:19 berni via Digitalmars-d-learn napsal(a): Is it possible to force a function to be inlined? Comparing a C++ and a D program, the main difference in speed (about 20-30%) is, because I manage to force g++ to inline a function while I do not find any means to do the same on D. yes https://wiki.dlang.org/DIP56 pragma(inline, true) doesn't work out well: int bar; void main(string[] args) { if (foo()) {} } bool foo() { pragma(inline, true) if (bar==1) return false; if (bar==2) return false; return true; } with dmd -inline test.d I get test.d(8): Error: function test.foo cannot inline function When I remove -inline, it compiles, but seems not to inline. I cannot tell from this small example, but with the large program, there is no speed gain. It also compiles with -inline when I remove the "if (bar==2)...". I guess, it's now really inlining, but the function is ridiculously short... I havn't tried the approach with templates yet, due to my lack of understanding templates.
Re: Force inline
On Monday, 20 February 2017 at 13:48:30 UTC, ketmar wrote: anyway, in my real-life code inlining never worth the MASSIVELY increased compile times: speedup is never actually noticeable. if "dmd -O" doesn't satisfy your needs, there is usually no reason to trying "-inline", it is better to switch to ldc/gdc. Probably you're right. I'm using gdc anyway for non-developement compiles. I was just curious how much that -inline switch of dmd is worth. (Answer: Yet, almost nothing. And knowing, that it is buggy together with -O even less than that.) When comparing dmd and gdc the results where both almost the same: 29 seconds. (As a reference: C++ is 22 seconds.) With gdc I got a good improvement when using -frelease additionally to -O3 (now it's 24 seconds). The inline-pragma didn't change anything. On Monday, 20 February 2017 at 17:12:59 UTC, H. S. Teoh wrote: Having said all that, though, have you used a profiler to determine whether or not your performance bottleneck is really at the function in question? Yes, I did. An well, yes I know: Good design is much more important, than speed optimization. And by obeying this, I found out, that by changing the order of the conditions used in that particular function, I could reduce the duration by 2 more seconds... (And in case you wonder, why I bother about 2 seconds: It's a small example for testing purpose. There are larger ones where this could easily be hours instead of seconds...)
Checking, whether string contains only ascii.
In my program, I read a postscript file. Normal postscript files should only be composed of ascii characters, but one never knows what users give us. Therefore I'd like to make sure that the string the program read is only made up of ascii characters. This simplifies the code thereafter, because I then can assume, that codeunit==codepoint. Is there a simple way to do so? Here a sketch of my function: void foo(string postscript) { // throw Exception, if postscript is not all ascii // other stuff, assuming codeunit=codepoint }
Re: how to pass stderr to core.stdc.stdio.fileno
As I cannot find any PM-feature in this forum and don't know how to contact you else, I'm hijacking this thread to give you some feedback... On Friday, 17 February 2017 at 19:16:44 UTC, Adam D. Ruppe wrote: Yes, that is my documentation fork, it has a search feature if you do dpldocs.info/some_term and it tries to be easier to read and navigate, let me know how you like it! I tried dpldocs.info/max looking for a function that gives the maximum of two or more values. I got a lot of results, but non of them was, what I was looking for. Meanwhile I found it, namely this one: http://dpldocs.info/experimental-docs/std.algorithm.comparison.max.html Maybe you can figure out, why this is not included in the search result?
Re: Checking, whether string contains only ascii.
On Wednesday, 22 February 2017 at 21:23:45 UTC, H. S. Teoh wrote: enforce(!s.any!"a > 127"); Puh, it's lot's of possibilities to choose of, now... I thought of something like the foreach-loop but wasn't sure if that is correct for all utf encodings. All in all, I think I take the any-approach, because it feels a little bit more like looking at the string at a whole and I like to use enforce. Thanks for all your answers!
Re: Checking, whether string contains only ascii.
On Thursday, 23 February 2017 at 17:44:05 UTC, HeiHon wrote: Generally postscript files may contain binary data. Think of included images or font data. So in postscript files there should normally be no utf-8 encoded text, but binary data are quite usual. Think of postscript files as a sequence of ubytes. As far as I know, images and font data have to be in clean7bit too (they are not human readable though). But postscript files can contain preview images, which can be binary. I know about this. I just tried to keep my question simple -- and actually I'm only testing part of the postscript file, where I know, that binary data must not occur.
Building a project with CMAKE
I'm using CMAKE to build my project. With https://github.com/dcarp/cmake-d this works almost. The only thing I do not manage to get working is running cmake in release mode. When I use -DCMAKE_BUILD_TYPE=Release I get some linker errors, which I do not get, when compiling manually. (In both cases gdc/linux is used.) I allready could figure out, that it's due to the -O3 compiler flag used in release mode. It looks like cmake compiles all *.d files separately and while doing so, removes some functions when optimizing them. Later, when linking everything together, they are missing. (But I'm not sure on this.) Here is my project: https://github.com/crocopaw/croco/tree/devel Anybody here who has experience with CMAKE and D and could help?
Re: Building a project with CMAKE
On Tuesday, 28 February 2017 at 17:09:28 UTC, berni wrote: I'm using CMAKE to build my project. [...] Just a note: I now asked the same question on the cmake mailing list. Maybe, it's the better place to do so...
Re: Building a project with CMAKE
On Thursday, 2 March 2017 at 09:13:40 UTC, berni wrote: Just a note: I now asked the same question on the cmake mailing list. Maybe, it's the better place to do so... After some help of cmake people and a morning of more investigations, I'm quite sure I found a bug in gdc. Meanwhile I've got a small example that compiles with gdc but leads to a linking error when compiled with -O3.
Re: Building a project with CMAKE
On Friday, 3 March 2017 at 13:21:56 UTC, Seb wrote: Is there any specific reason why you can't use DMD or LDC? gdc produces faster binaries. ;-) I've got installed the other two compilers too and they work.
Re: Building a project with CMAKE
On Friday, 3 March 2017 at 20:10:25 UTC, Ali Çehreli wrote: Which would put gdc in between the two. Is your experience different? Actually, I've got not much experience. A few weeks ago I ran a test where ldc was in between dmd and gdc. But I missed the -release flags then. With that flag it's faster, but still slower than gdc on that one (B below). With an other testcase, where I compared them, gdc and ldc are on equals speed (A below). A) dmd 52s, gdc 22s, ldc 22s B) dmd 432s, gdc 280s, ldc 310s
Re: Building a project with CMAKE
On Saturday, 4 March 2017 at 10:02:15 UTC, Johan Engelen wrote: If you think you have a good testcase, it's nice for compiler devs like me to open a new thread about the difference that you found between the compilers (so that we can try and improve things). I'm not sure, if my "testcase" is generally a good one. Here is some background: In the last 10 years I developed about 200 programs for checking logical puzzles (like sudoku), all written in java. About a year ago I decided to make these programs free software. But as I have to refactor them anyway and I dislike java meanwhile I decided to change the language when doing so. I decided on a special puzzle type, called double mine (similar to minesweeper, but in every row and column, there have to be exactly two mines and mines may not touch, not even diagonally), to check out different languages. Speed was just one criterion when doing this. At that time D wasn't among the candidates, because I did not know of this language at all. I added D later (with almost no knowledge about D) and checked out all three compilers. If you think, this program could be usefull for you, I can email it to you...
Files as buffered InputRange
I'd like to process a (binary) file as a buffered InputRange but I havn't found anything yet. Is there anything or do I have to write it on my own?
Re: Files as buffered InputRange
On Friday, 5 July 2019 at 17:57:39 UTC, Les De Ridder wrote: File.byChunk[1] should do the trick. [1] https://dlang.org/library/std/stdio/file.by_chunk.html Not sure, if this is, what I'm looking for. I'd like to do something like buffered_file.map!(a=>2*a).writeln(); When I understand it right, with byChunk I'll have to take care about the end of the buffer, myself...
Re: Files as buffered InputRange
On Friday, 5 July 2019 at 18:45:01 UTC, Les De Ridder wrote: On Friday, 5 July 2019 at 18:29:36 UTC, berni wrote: On Friday, 5 July 2019 at 17:57:39 UTC, Les De Ridder wrote: File.byChunk[1] should do the trick. [1] https://dlang.org/library/std/stdio/file.by_chunk.html Not sure, if this is, what I'm looking for. I'd like to do something like buffered_file.map!(a=>2*a).writeln(); When I understand it right, with byChunk I'll have to take care about the end of the buffer, myself... You could use `joiner` from std.algorithm, e.g. buffered_file.byChunk(4096).joiner.map!(a => 2 * a).writeln; That's it. Thanks!
Is there something like a consuming take?
I want to copy the first n items of a range to an array, removing these items from the range. This works: foreach (i;0..n) { data ~= r.front; r.popFront(); } but looks a little bit arkward. I came up with this now: data = r.take(n).array; This works partly, because the values of r are not consumed. So I have to call afterwards: r = r.drop(n); Now I wonder, if it is possible to do this with one single call, something like data = r.take_consuming(n).array; Does there something like this exist?
struct inside struct: Is there a way to call a function of the outside struct from the inner struct?
struct A { void c() {} struct B { void d() { c(); } } } When compiling this with rdmd I get the message: "Error: this for c needs to be type A not type B". Is there a way to call c from d?
Re: For loop with separator
On Thursday, 4 July 2019 at 17:00:33 UTC, Q. Schroll wrote: The prime example is printing the comma when printing a list: There is one between any two elements, but neither is one at front or behind the last one. If it is just for printing commas in between, you can use range.join(", ") https://dlang.org/phobos/std_array.html#.join
Re: Is there something like a consuming take?
On Saturday, 6 July 2019 at 11:48:51 UTC, a11e99z wrote: sure auto take_consuming( R )( ref R r, int cnt ) { auto tmp = r.take( cnt ).array; r = r.drop( cnt ); return tmp; } don't thank Doesn't look like what I'm looking for, as it is exactly the same I allready found. Maybe I need to explain, what I dislike with this approach: take() calls popFront n times and drop() calls popFront another n times giving a total of 2n times (depending on the underlying range, this might cause lot's of calulcations be done twice. The first version with the foreach loop calls popFront only n times.
Re: struct inside struct: Is there a way to call a function of the outside struct from the inner struct?
Now I found this: https://forum.dlang.org/thread/eobdqkkczquxoepst...@forum.dlang.org Seems to be intentional, that this doesn't work. In my case I'm able to move d() into the outer struct...
Re: Is there something like a consuming take?
Now it's getting weird. Meanwhile I encountered, that take() sometimes consumes and sometimes not. Where can I learn, what is the reason behind this behavior? And how can I handle this?
Re: Is there something like a consuming take?
A small example showing this strange behaviour: import std.stdio; import std.algorithm.iteration; import std.range; enum BUFFER_SIZE = 1024; void main(string[] args) { auto a = (new File(args[1])) .byChunk(BUFFER_SIZE) .joiner; writeln(a.take(5)); writeln(a); } Using a file, containing the bytes 1 to 10 I get: [ 1, 2, 3, 4, 5 ] [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] take does not consume. When I now change BUFFER_SIZE to 2 I get: [ 1, 2, 3, 4, 5 ] [ 5, 6, 7, 8, 9, 10 ] Now the first two buffers have been consumend and the third ([5, 6]) not. Feels like a bug in Phobos. But maybe I do not understand, what's happening and this is correct behaviour. Can anyone explain or confirm, that this is a bug?
Re: Is there something like a consuming take?
On Saturday, 6 July 2019 at 14:48:04 UTC, Adam D. Ruppe wrote: [...] So this is a case of input range behavior - always consuming the underlying file - combined with buffering of two elements at once, leaving 5,6 behind, and the reuse of the buffer meaning you see that 5,6 again on the next call. Thanks for clearifing what happens. In my oppinion the behaviour of take() should be better defined. It's clear, that take() returns a range with the first n elements of the underlaying range (and that is done lazily). But it's not specified what happens with the underlaying range. As the behaviour is unpredictable (or at least hard to predict), one should assume, that the underlaying range is completely destroyed by take(). This makes take() much less usefull, than it could be, in my eyes. :-(
Re: Is there something like a consuming take?
I start to understand: A (lazy) range is something like a voucher: byChunk() does not provide the data immediately, but only a voucher to hand you a chunk (an array of 2 bytes in my example above) a time. This voucher is passed to joiner(), which keeps that voucher and hands me out a new voucher for a byte a time (called "a" in my example above). This voucher is now passed to take(), whick again keeps that voucher and hands me out yet an other voucher for a byte a time, but limits itself to 5 items. Up to now nothing has happend, but the exchange of that vouchers. Now when writeln() is called, it shows take() that voucher and says: "Give me the first of your numbers". take() uses his voucher to do the same with joiner(), which uses its voucher to get the first chunk of byChunk(), takes the first byte of that chunk and hands it to take() and take() hands it to writeln(). Now writeln() uses it's voucher once again, to get the next byte. take() asks joiner() again, but this time joiner() does not ask byChunk(), because it still has one number left in the chunk it got when asking the last time. Now joiner() uses this second byte to hand it back. And so on. After writeln() finished I'm doing something evil: I use a private copy of that voucher, that I allready handed to take() to use it myself. That's sort of stealing back. And hence the results are more or less unpredictable. Especially, when I use this copy, before take() finished it's job, as Jonathan M Davis points out. My misthinking was to assume, that my copy of the voucher is still the same as the voucher, that take() owns after having handed out the 5 items, so I can use it to get the other items. If it where possible to ask take() to hand me back it's voucher, I could do it with this voucher, but I don't see a possibility to get that voucher back. What I actually want to do, when using take(), is not to get a new voucher, but I want to keep my voucher and just use this voucher to get the first 5 items - take() doesn't do that, so I've got to write my own function which cannot be lazy. Or better: I'd like to hand in my voucher and get back two vouchers, one for the first 5 bytes and one for the rest. That's actually, what I thought, take() is doing...
Re: Is there something like a consuming take?
On Sunday, 7 July 2019 at 09:01:53 UTC, Jonathan M Davis wrote: Without slicing, that's impossible without iterating over the elements multiple times. That's what I thought too, but meanwhile I think it is possible. To get it working, the second range needs to know about the first one and when the second one is queried the first time it has to notify the first one, that it has to remove all remaining items from the underlying range (and in case it still needs them, save them) and never use it again. The advantage of this setup over copying the items immediately is some sort of laziness. It might happen, that the second one will never query or it might happen, that the first one finished allready when the second one queries. In this cases no additional memory is needed. Even if the second one is queried before the first one finished, the needed buffer might be much smaller.
Re: Is there something like a consuming take?
On Sunday, 7 July 2019 at 21:55:17 UTC, Jonathan M Davis wrote: Having one range know about the other isn't enough. That just means that the take range would tell the other range that it had popped an element off, and then the other would know that it had to pop an element off. That still involves popping the same element on different ranges twice. Sounds like you didn't understand what I meant. So I tried to implement what I had in mind and I have to confess, that there is something about ranges that I do not understand yet: import std.stdio; import std.array; void main() { auto a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; call(a,5); } void call(T)(ref T range, int c) { struct Take { T* take_range; int count; @property bool empty=false; @property auto front() { return (*take_range).front; } void popFront() { (*take_range).popFront(); if (--count<=0) empty=true; } T* get_range() { assert(count==0); while (!empty) popFront(); return take_range; } } auto take = Take(&range,c); //writeln(take); while (!take.empty) { write(take.front); take.popFront(); } auto original_range = take.get_range(); writeln(*original_range); } Running this program leads to 12345[6, 7, 8, 9, 10, 11, 12, 13, 14, 15] as expected. But when I replace that loop at the bottom by writeln(take) the assertion in get_range fails (count==5). As all the functions are called in the same order by both the loop and writeln, I confess, that writeln somehow manages to use a copy of "take" although this isn't a ForwardRange and copying should therefore not be possible. You can try mucking around with your own implemention of take if you want, but I'd suggest that you're just better off taking the approach that it's expected that if you use take, I't not about improving or doing things different. It's just about me understanding, what happens.
Re: Is there something like a consuming take?
Hurray, it works! :-) https://run.dlang.io/is/2GMq34 I have to use classes to avoid copying when arguments are passed to a function. (And yes, there should of course be much more checks, especially when there are to few elements in the original range. And it could be speed improved and so on... I wanted to keep it simple.)
Re: Help me decide D or C
On Wednesday, 31 July 2019 at 18:38:02 UTC, Alexandre wrote: Should I go for C and then when I become a better programmer change to D? Should I start with D right now? In my oppinion C should have been deprecated about 50 years ago and it's not worth while to learn it if you are not interested in the history of programming or you have to learn it, because you need to maintain software which is allready written in C. But that's my oppinion; others may have a different sight. I would recommend to start immediately with D (using the book of Ali, which has allready been mentioned). When you've got mastered D you will not have any problems switching to an other language. And you don't need to know everything about D to write programs. For example you do not need to use templates in the beginning. You might find out a strange looking syntax for type conversion "to!string(17)" with this exclamation mark in between, which you can just accept and us as is, without having to understand what it's good for. I would even go further and state, that learning C first will become a burden instead of a help.
Re: Help me decide D or C
On Wednesday, 31 July 2019 at 18:38:02 UTC, Alexandre wrote: Should I go for C and then when I become a better programmer change to D? Should I start with D right now? In my oppinion C should have been deprecated about 50 years ago and it's not worth while to learn it if you are not interested in the history of programming or you have to learn it, because you need to maintain software which is allready written in C. But that's my oppinion; others may have a different sight. I would recommend to start immediately with D (using the book of Ali, which has allready been mentioned). When you've got mastered D you will not have any problems switching to an other language. And you don't need to know everything about D to write programs. For example you do not need to use templates in the beginning. You might find out a strange looking syntax for type conversion "to!string(17)" with this exclamation mark in between, which you can just accept and us as is, without having to understand what it's good for. I would even go further and state, that learning C first will become a burden instead of a help.
Re: Why does choose not work here
On Thursday, 1 August 2019 at 21:26:10 UTC, Matt wrote: Anyone have any other thoughts? I tried to simplify your example a little bit: import std.stdio; import std.range; import std.algorithm; auto myFilter(R1, R2)(R1 a, R2 b) { return a.filter!(c => c==b.front); } struct A { int[] starts; auto intervalRange() @property { return starts; } } auto uniqIntervalsA(A primary, A* previous) @property { return choose(previous is null, primary.intervalRange, primary.intervalRange.filter!(a => a==previous.intervalRange.front)); } auto uniqIntervalsB(A primary, A* previous) @property { return choose(previous is null, primary.intervalRange, primary.intervalRange.myFilter(previous.intervalRange)); } unittest { auto a1 = A([1]); writeln(uniqIntervalsA(a1,&a1)); writeln(uniqIntervalsA(a1,null)); writeln(uniqIntervalsB(a1,&a1)); writeln(uniqIntervalsB(a1,null)); } The strange thing is, that even if you replace "return a.filter!(c => c==b.front);" by "return a.filter!(c => true);" the problem remains (but now you can use lazy). As I'm not an expert myself, I'm not sure how to analyze this. But I think, both parameters to "choose" are evaluated (that is they are not lazy), but "myFilter" uses it's parameter immediately to give "b" a value, while "filter" just hands in an anonymous function without using it ever. Hope, this helps to get further down the way to a solution...
Re: Help me decide D or C
On Friday, 2 August 2019 at 14:05:20 UTC, SashaGreat wrote: On Friday, 2 August 2019 at 12:28:45 UTC, berni wrote: On Wednesday, 31 July 2019 at 18:38:02 UTC, Alexandre wrote: Should I go for C and then when I become a better programmer change to D? Should I start with D right now? In my oppinion C should have been deprecated about 50 years ago ... I stopped there. How could you have deprecated a language 50 years ago since was first released in '72 (47 years ago). Yes, that was intentional. What I wanted to say is, that I think, that it would have been better, if C was never invented at all... In that case, there would have been space for an other language for writing operating systems, without that much bugs in its design. (But one never knows afterwards...)
string to ubyte[]
I've got a function which takes two strings and should return them as a ubyte[] with additional zero bytes in between and around. This works: ubyte[] convert_string_pair(string first, string second) { auto b = new ubyte[](0); b ~= 0x00 ~ first ~ 0x00 ~ second ~ 0x00; return b; } But I think it would be more elegant to do it in a single return statement, but unfortunately this does not work: ubyte[] convert_string_pair(string first, string second) { return 0x00 ~ first ~ 0x00 ~ second ~ 0x00; } The reason is, that this expression creates a string and not a ubyte[]...
Merging two associative arrays
I've got two associative arrays and want to get a new one, which is created out of both of them: This works: string[int] a = [1:"one", 7:"seven"]; string[int] b = [5:"five", 9:"nine"]; string[int] tmp = a.dup; foreach (k,v;b) tmp[k] = v; assert(tmp==[1:"one", 7:"seven", 5:"five", 9:"nine"]); But is there something easier, especially without making that "tmp" explicit. I hoped for a~b, but that didn't work. (I allready know, that there aren't duplicated keys, if that matters.)
Re: Merging two associative arrays
On Saturday, 24 August 2019 at 19:55:48 UTC, a11e99z wrote: auto ab = a.byPair.chain( b.byPair).assocArray ? Not sure, if it is simpler, but a least without tmp. :) Thanks.
.fflush() in stdio.d
Out of curiosity: Browsing the source of stdio.d I found that flush() is implemented by calling fflush from some C++ library. What I don't understand: Why is the call to fflush preceded by a dot?
Re: .fflush() in stdio.d
On Monday, 26 August 2019 at 09:14:23 UTC, Jonathan M Davis wrote: The dot makes it so that it's specifically referencing a module-level symbol (be it in that module or an imported module) instead of a local or member symbol. Ah, thanks. Now it makes sense! :)
+= on associative arrays leads to surprising result
import std.stdio; void main() { real[int] a; a[0] += 100; writeln(a); } results (independed of the used compiler) in [0:100] I was a little bit surprised, because a[0] += 100 should be the same as a[0] = a[0]+100, which leads to a range violation error. Furthermore, as we work with real, I'd expected the result to be NaN... Is this a bug? I ask, because it would be quite convenient to use it the way it works now. An alternative I found, would be to use object.update. But there I've to declare the 100 twice which results in code duplication: a.update(0,()=>100.0L,(ref real v)=>v+100.0L); Hence, my best solution needs two lines: if (0 !in a) a[0] = 0; a[0] += 100; What's your oppinion on this?
Re: += on associative arrays leads to surprising result
On Tuesday, 27 August 2019 at 16:45:53 UTC, Samir wrote: I never understood why the intial value of floats, doubles and reals was NaN. That's for detecting uninitialised variables. If the result of a calculation is NaN, it's likely, that you forgot to initialise the variable.
Re: Sort Associative Array by Key
On Tuesday, 27 August 2019 at 16:25:00 UTC, Samir wrote: As I've mentioned on the list before, I really struggle to understand how some of the std.algorithm functions such as `map` work when combined with things like `array`, `sort` and especially `zip` but really appreciate the support I find here on the forum. A few months ago I stuggled with that too. Meanwhile I think I got it. Let's examine just the first step in this sequence: writeln(foo.byPair); This leads to [Tuple!(string, "key", int, "value")("BZP", 5), Tuple!(string, "key", int, "value")("VXE", 8), Tuple!(string, "key", int, "value")("JLC", 2)] Well, this look like an array of tuples, each tuple containing a key and a value. I assume, that you understand tuples, I think, they are not the problem here. The problem arises, because the result of "foo.byPair" isn't an array. Actually writeln converts the result to an array, before printing it (or at least it pretends to do so). You can see this with: writeln(typeof(foo.byPair).stringof); Which is: MapResult!(__lambda2, Result) Ooops, what's that? Having a look at the documentation isn't very instructive (at least at beginners level): auto byPair(AA)(AA aa) if (isAssociativeArray!AA); That's almost all you get. Almost, because the description mentions, that the return value is a forward range. Ah, it's a range. I'm not sure, how much you know about ranges. If you want to understand that stuff, you should study them. E.g. try to write some ranges of your own. When thinking of a range, I imagine it as sort of a voucher for something like an array. You can use that voucher to get elements from that array. In case of an forward range, you are restricted to get the elements ony by one from the beginning. You get them by using the function front(), which all ranges provide. Let's try it: auto something = foo.byPair; writeln(something.front); And we get: Tuple!(string, "key", int, "value")("BZP", 5) That's indeed the first of our elements. We don't know yet, what this range is doing behind the sceens. But I can tell you: When calling byPair it hasn't done much: It just signed that voucher and handed it out to you (that's called lazy evaluation, contrary to eager evaluation). Maybe you never use that voucher. In that case it would be wasted time to calculate all the elements, that are never used. The moment you call front, that range starts to do some of the work. It assembles the first item of the range and hand's this out to you. Then it stops again - the other items are not yet calculated. That's done, when you call front again (but before you need to call popFront, to remove the first item, else you would get the item, you allready have, once again). And so on. Now we know, how to use this range and that's what "array" does: It calls front and popFront as long as there are more elements (this can be checked by calling empty on the range), and puts them into an array. But what we don't understand yet is that strange type of the range: MapResult!(__lambda2, Result). For that, we should have a look at the implementation (I'm using http://dpldocs.info/experimental-docs/std.array.byPair.html for that, because it has a link to the documentation at the bottom), we find out, that byPair is implemented using byKeyValue and map: return aa.byKeyValue .map!(pair => tuple!("key", "value")(pair.key, pair.value)); byKeyValue is defined in object, which has no source code - I guess it's implemented directly in the compiler somehow. By using typeof, we find out that the type is "Result" and by using writeln we find out, that the result of byKeyValue looks like an array of Pairs of pointers. Again it's a range, that we can use like above. This range (think again of a voucher) is now send to map. Map needs, beside this range, a function. You could write that function like: auto make_tuple(Pair pair) { return tuple!("key", "value")(pair.key, pair.value); } Than the above could be written as return aa.byKeyValue.map!(make_tuple); Beside the fact, that I cannot find the definition of Pair (and therefore would need to make a template instead of the function), it's not necessary to write that function explicitly. There is a way, to write functions more compressed, namely by using =>, like it's done above. Those functions are called lambda-functions (because at some places a greek lambda symbol was used for the function parameter). Now, map is lazy too. It just remembers that function, the "voucher" it got and hand's you an other voucher. That's all. This new voucher is called "MapResult", which is actually a struct with functions "front", "popFront" and "empty" (and some more, but we don't care). And this struct has two template-parameters, namely a function and a range. We know that range already, it's Result from byKeyValue. And that function, which has no name, got the name "__lambda2" from th
Is removing elements of AA in foreach loop safe?
Iterating of some structure and removing elements thereby is always errorprone and should be avoided. But: In case of AA, I've got the feeling, that it might be safe: foreach (k,v;ways) if (v.empty) ways.remove(k); Do you agree? Or is there a better way to achieve this?
Re: Is removing elements of AA in foreach loop safe?
On Friday, 30 August 2019 at 15:00:59 UTC, Paul Backus wrote: Whether you actually get an error at runtime depends on the load factor of the AA. If it drops below a certain threshold, the AA will be resized [1], and its original memory will be freed [2]. It could still work, depending on how the foreach loop is implemented. If the keys were stored away before starting the loop it would work. But for one thing, it isn't implemented that way and for the other, one shouldn't rely on it, because the implementation could change. What I hoped for, was, that the specs enforce somewhere, that this is to be implemented in a safe manner. I'll replace this loops by something better, e.g. the mentioned filter. But I've never worked with AAs and filters yet. Will see, if I manage to do that. Else I'll probably just copy the keys and use them for an independent loop.
adding delegate to opApply
I've tried to make a small example, but it's not easy to get this reduced further. At least I didn't manage. The following program can also be found at https://run.dlang.io/is/p6l7xN void main() { auto foo = Ways([Way([8,2,3,0]),Way([4,6,2]),Way([4,7,2,6])]); foo.remove_odds(); assert(foo==Ways([Way([8, 2]), Way([4, 6, 2]), Way([4]), Way([0]), Way([2, 6])])); } struct Ways { Way[] ways; void remove_odds() { Way[] new_ways; foreach (ref way;ways) foreach (point, void delegate(void delegate(Way way)) remove;way) if (point%2==1) remove(delegate(Way way) {new_ways ~= way;}); ways ~= new_ways; } } struct Way { int[] points; auto opApply(int delegate(int, void delegate(void delegate(Way way))) work) { size_t[] remove; void delegate(Way) add_new_way; foreach (index,point;points) if (auto result=work(point,(void delegate(Way) anw){remove~=index; add_new_way=anw;})) return result; import std.algorithm.sorting: sort; foreach (index;remove.sort!("a>b")) { add_new_way(Way(points[index+1..$])); points = points[0..index]; } return 0; } } I need to pass the delegate add_new_way somehow to opApply. Here I managed this, by adding this delegate to the remove-delegate and safe it away for further use. This works, because if remove is never called, add_new_way is not used either. But it's a little bit awkward. Is there a better way, to achieve this? (Note 1: In the real world, point%2==1 is a more complex function call. Note 2: The order of elements in Way[] way doesn't matter, if that makes things easier.) Maybe it's possible to work with something like std.algorithm.iteration.splitter instead of those loops and opApply. But splitter takes an element or a range, not a predicate.
Re: adding delegate to opApply
On Monday, 2 September 2019 at 14:20:11 UTC, Paul Backus wrote: If you have an existing delegate that you want to use with opApply, the easiest way is like this: void delegate(Thing) myDelegate = ...; foreach(thing; things) { myDelegate(thing); } // Equivalent to: things.opApply((Thing t) => myDelegate(t)) Thanks for your answer. It's not exactly, what I was looking for, but meanwhile I think, the whole idea was not reasonable. I meanwhile returned to using a normal function call instead of opApply, which makes it easy to pass a delegate as one of the parameters.
Re: Is removing elements of AA in foreach loop safe?
On Tuesday, 3 September 2019 at 20:06:27 UTC, Ferhat Kurtulmuş wrote: I know, it is foreach loop in question. How about using a reverse for loop like: for (size_t i = arr.length ; i-- > 0 ; ){ arr.remove(i); } This would be good, if it where for slices. But with associative arrays, this doesn't work. :-(
getting rid of immutable (or const)
I still struggle with the concept of immutable and const: import std.stdio; void main() { auto p = Point(3); auto q = p.x; writeln(typeof(q).stringof); } struct Point { @property immutable long x; } The type of q is immutable(long). But I need a mutable q. I found two ways: a) long q = p.x; b) auto q = cast(long)p.x; Either way I've to specify the type "long" which I dislike (here it's not a real burdon, but with more complicated types it might be). Is there a way, to make q mutable without having to write the type explicitly?
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 08:16:08 UTC, Daniel Kozak wrote: in this case you can just use: auto q = cast()p.x; Ahh, great! :-) But that directly gets me to the next question: import std.stdio; void main() { Point[] q = [Point(1),Point(3),Point(2)]; import std.algorithm.searching: minElement; writeln(q.minElement!(a=>a.x).x); } struct Point { @property immutable long x; } This doesn't compile: /usr/include/dmd/phobos/std/algorithm/searching.d(1365): Error: cannot modify struct extremeElement Point with immutable members /usr/include/dmd/phobos/std/algorithm/searching.d(1307): Error: template instance `test.main.extremum!(__lambda1, "a < b", Point[], Point)` error instantiating /usr/include/dmd/phobos/std/algorithm/searching.d(3445): instantiated from here: extremum!(__lambda1, "a < b", Point[]) test.d(8):instantiated from here: minElement!((a) => a.x, Point[]) Any idea, how to get around this?
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 08:44:35 UTC, berni wrote: This doesn't compile: [...] Any idea, how to get around this? Found the answer myself: q.map!(a=>a.x).minElement; :-)
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 08:56:42 UTC, berni wrote: [..] And one more question: import std.algorithm: reverse; writeln(q.reverse); Here the compiler complains with: test.d(8): Error: template std.algorithm.mutation.reverse cannot deduce function from argument types !()(Point[]), candidates are: /usr/include/dmd/phobos/std/algorithm/mutation.d(2483): std.algorithm.mutation.reverse(Range)(Range r) if (isBidirectionalRange!Range && (hasSwappableElements!Range || hasAssignableElements!Range && hasLength!Range && isRandomAccessRange!Range || isNarrowString!Range && isAssignable!(ElementType!Range))) I allready tried to use q.dup.reverse but that didn't work either. How to get this working? (I hope I don't annoy you by asking that much questions, but I've got the feeling, that I've got only two choices: To shy away from using immutable (like I did in the last three years) or ask a lot of questions in the hope of understanding what's going on...
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 10:47:56 UTC, Simen Kjærås wrote: https://dlang.org/library/std/range/retro.html Yeah, that worked. Thanks. :-) Don't worry about asking questions OK. Then here's the next one: Point[long] q; q[1] = Point(3); Leads to: test.d(7): Error: cannot modify struct q[1L] Point with immutable members
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 11:22:15 UTC, drug wrote: 05.09.2019 14:17, berni пишет: Point[long] q; q[1] = Point(3); Leads to: test.d(7): Error: cannot modify struct q[1L] Point with immutable members But why do you try to modify immutable data? What is your point? Could you describe you use case? That's probably, what I don't understand. I've got a Point, which should not be modified. I put it in a container (q) and later I get it out there again. It should still be the same Point as before. I modify the container, not the Point, don't I?
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 12:15:51 UTC, drug wrote: One solution could be using either pointer to `const(Point)` or class here (to avoid pointer using) https://run.dlang.io/is/rfKKAJ OK. This are two solutions and although I'll probably not going to use any of those (due to other reasons), I still don't understand, why the original approach does not work. If I've got a book an put it in a box and later I'll get it out again, it's still the same book. So why has a struct changed when I put it into an AA and get it out again? It's not supposed to change...
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 13:27:55 UTC, drug wrote: [...]when you put it into an AA you modify old value Why?!? :-o When putting it into an AA it will be copied to a different place in memory, but the value is still the same, it's not modified. Sorry, but I still think, there is something fundamentally wrong about how I think about immutability. But if you just want to initialize an AA by immutable members then this can be usefull to read https://dlang.org/spec/hash-map.html#runtime_initialization Well, yes and no. I want to initialize an AA with structs that contain immutable members. And that AA resides at runtime inside of a function body. I don't see, how this can be done with he approach given by the link. :-(
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 15:48:40 UTC, Ali Çehreli wrote: That's the misunderstanding: The existing object is assigned over. The address is the same: void main() { int[int] aa; aa[1] = 1; const oldPointer = (1 in aa); aa[1] = 11; assert(oldPointer is (1 in aa)); // Passes } First, I thought, I've got understood it now, but then I wrote this little program and the result was not, what I thought it would be: void main() { int[int] a; immutable int b = 17; a[1] = b; // <-- expecting error here const oldPointer = (1 in a); immutable int c = 10; a[1] = c; assert(oldPointer is (1 in a)); Point[int] d; immutable Point e = Point(17); d[1] = e; // <-- but error is here } struct Point { immutable int x; } What's the difference? I can put an immutable int in an AA and I can overwrite it (pointer is still the same), but I can't do that with a struct, having an immutable member. When I remove that immutable inside of the struct it works. ?!? While writing this, I had an other idea, namely, that changing d[1] would make e to be something different (x inside Point is mutable this time): Point e = Point(17); d[1] = e; d[1] = Point(19); writeln(e); But it's still 17. const or immutable members make structs unassignable. But why? Here: Point[3] f; f[0] = Point(3); I understand, that I cannot change f[0], because it's allready got a default value and that value would be overwritten. But in an aa, that member does not exist before putting the Point in there, hence there is nothing, that could be overwritten... Whether the members of a type are const or immutable should not be dictated by where the objects of that type will be used. If it makes sense otherwise, sure... I'm not sure if I understand that right. It's sort of an advice on how to decide if one want's to make a member immutable or not, is it? If you are worried about existing elements being modified, you can provide a different container that wraps an AA, but provides an opIndex that returns 'ref const(T)'. That would solve the immutability of the elements in the container. No, I don't worry about such things. My program runs smoothly when I don't make that members immutable. And I could perfectly live with that But that's the maxim I used the last three years: "If avoidable, don't use 'immutable' at all, it only causes problems." But that is not satisfiable. Because if immutable were that useless, why would it exist at all? So I would like to understand, what's happening; being able to predict, what works and what not. At the moment it's almost always the opposite of what I think it should be...
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 20:10:03 UTC, ag0aep6g wrote: You're not putting an immutable int into an AA. You're copying the value of an immutable int to a mutable one. but I can't do that with a struct, having an immutable member. When I remove that immutable inside of the struct it works. ?!? `Point` is effectively the same as `immutable long`. A better simile would be this: `immutable(int)[int] a; a[1] = 17;`. And now you get the same error. You can't overwrite the element, because its immutable. Ah, the point is not, that my object contains an immutable element, but that the base type of the AA is a type with an immutable element! I understand now. Thanks a lot!
Re: getting rid of immutable (or const)
On Thursday, 5 September 2019 at 21:22:12 UTC, Ali Çehreli wrote: If it makes for the type to have immutable (or const) members, then fine; with the understanding that objects of that type cannot be assigned or mutated any other way, we can define them like that. What I meant is, because we want to use such a type in an AA and we don't want the element to change should not dictate the type's members. Using in an AA should be yet another usage of the type. Got it. ;-) > if immutable were that useless, why would it exist > at all? immutable is useful: You can have immutable objects, immutable AAs (different from what we are discussing here), etc. So, what I'm just trying all the time is not to have a struct with immutable elements but a immutable struct-object with mutable elements. I think, that's what I confused all the time. As a general rule, I never make members const or immutable; this is a guideline that I carried over from C++. I have almost no experience with C++, but I just accept that as a good advise. After all that discussion here, it seems to be sound. Thank you very much too! I think I made a big jump forward in understanding the concept of immutability in the last 24 hours. :-)
Re: getting rid of immutable (or const)
On Friday, 6 September 2019 at 08:47:07 UTC, Kagamin wrote: Physical objects work like reference types. A place on bookshelf is at one coordinate and a book is at another coordinate, you don't copy the book, you fill a place on bookshelf with a reference to the book. So it's more like a piece of paper, where there is place for a note. And when assigning, I erase that note (whatever it was) and write the new note at that place. Got it! :-)
Re: Learning delegates
On Sunday, 8 September 2019 at 10:04:57 UTC, Joel wrote: I'm trying to understand delegates. Is there any good ways I can get a better understanding of them? I wrote a foreach loop using opApply. A side effect of that was, that after I managed to do this I understood delegates. :-)