Local static variables must have unique names within a function's scope.
The following seems to work in C++, but errors in D, why is that? int foo(int* num) { { static int x = 10; x += 1; *num += x; } { static int x = 20; // error: foo.x is already defined in another scope in foo x += 2; *num += x; } return 0; } https://dlang.org/spec/function.html#local-static-variables
Re: Local static variables must have unique names within a function's scope.
On Friday, 19 January 2018 at 11:02:01 UTC, tipdbmp wrote: The following seems to work in C++, but errors in D, why is that? int foo(int* num) { { static int x = 10; x += 1; *num += x; } { static int x = 20; // error: foo.x is already defined in another scope in foo x += 2; *num += x; } return 0; } https://dlang.org/spec/function.html#local-static-variables 19.17.1.3 explains the fact that they need to have unique names, but doesn't provide a reason. Mostly, it's just a bad idea - it's very easy for a person reading the code after you've written it to get the two x's mixed up. -- Simen
Re: Local static variables must have unique names within a function's scope.
Mostly, it's just a bad idea - it's very easy for a person reading the code after you've written it to get the two x's mixed up. // example from: 19.17.1.3 void main() { { static int x; } { static int x; } // error { int i; } { int i; } // ok } I don't really see how the 'static' storage class would make 2 variables with the same name in different scopes "easier to mix up" compared to 2 variables with the same name in different scopes but declared without the 'static' keyword.
Program exiting from thread with infinite loop
I have the following that is supposed to pull and store info from a server every five minutes. It works if I move the body of deviceDownloader into main(). However when I try to spawn it in another thread it runs the function and then ends once it's done, like it's ignoring the while(true). I tried with std.parallelism, core.thread, vibe.d's concurrency library, but get the same result every time. Any idea how to better accomplish this? import std.net.curl; import device; import std.datetime.systime; impor std.concurrency; void deviceDownloader() { auto APIServer = HTTP(); APIServer.addRequestHeader("X-Auth-Token:", AuthToken); APIServer.onProgress = delegate int(size_t dl, size_t dln, size_t ul, size_t uln) { if (dl != 0) write("Progress: downloaded ", dln, " of ", dl, "\r"); return 0; }; while (true) { auto currentTime = Clock.currTime; if (currentTime.minute % 5 == 0 && currentTime.second == 0) retrieveDevices(URL, APIServer); // info retrieved and stored here } } void main() { spawn(&deviceDownloader); }
Re: Program exiting from thread with infinite loop
On Friday, 19 January 2018 at 17:05:44 UTC, Chris M. wrote: However when I try to spawn it in another thread it runs the function and then ends once it's done, like it's ignoring the while(true). It is probably terminating the child threads when the main one ends. Might help to have the main wait until the child dies too. But why are you putting it in a thread anyway? If the main is doing nothing than just waiting, might as well just keep the logic in there.
Re: Program exiting from thread with infinite loop
On Friday, 19 January 2018 at 17:17:28 UTC, Adam D. Ruppe wrote: On Friday, 19 January 2018 at 17:05:44 UTC, Chris M. wrote: However when I try to spawn it in another thread it runs the function and then ends once it's done, like it's ignoring the while(true). It is probably terminating the child threads when the main one ends. Might help to have the main wait until the child dies too. I tried putting an infinite loop inside main() as well, didn't seem to help. I'm guessing there's probably a better way to make the main thread wait? I'm pretty new to threads and whatnot. But why are you putting it in a thread anyway? If the main is doing nothing than just waiting, might as well just keep the logic in there. It'll be doing other things, this is just the first thing I've implemented.
Re: Program exiting from thread with infinite loop
On 01/19/2018 09:46 AM, Chris M. wrote: > I tried putting an infinite loop inside main() as well, didn't seem to > help. Another reason is an exception thrown in the child thread. If the exception is not caught, it will terminate the child thread and the main will not know anything about it. I have something about that here: http://ddili.org/ders/d.en/concurrency.html#ix_concurrency.exception,%20concurrency > I'm guessing there's probably a better way to make the main thread > wait? std.core.thread_joinAll is a way but you would want to tell the other thread to terminate first. https://dlang.org/phobos/core_thread.html#.thread_joinAll So, instead of while(true), try while(someCondition). In that case the main thread sets the condition e.g. by sending a message and then joins. Ali
Re: Local static variables must have unique names within a function's scope.
On Fri, Jan 19, 2018 at 02:16:24PM +, tipdbmp via Digitalmars-d-learn wrote: > > Mostly, it's just a bad idea - it's very easy for a person reading > > the code after you've written it to get the two x's mixed up. > > // example from: 19.17.1.3 > void main() > { > { static int x; } > { static int x; } // error > { int i; } > { int i; } // ok > } > > I don't really see how the 'static' storage class would make 2 > variables with the same name in different scopes "easier to mix up" > compared to 2 variables with the same name in different scopes but > declared without the 'static' keyword. I think this is more an implementational quirk than any deliberate decision on variable names being "easier to mix up". A static variable currently mangles to a combination of the function name and variable name, so if there are multiple static variables with the same name, their mangled names would collide. OTOH, it would really suck if non-static variable names can't be reused in nested scopes, because it would mean you have to invent new names for, say, loop variables for every loop in the same function: void func(int[100] a, int[100] b) { foreach (i; 0 .. 100) { a[i] = i; } foreach (i; 0 .. 100) { b[i] = i; } // this would fail } Fortunately this is not the case. However, the static variable case is annoying, and it's actually one case of a larger problem: void main() { foreach (i; 0 .. 10) { struct S { int x; } auto s = S(i); } foreach (i; 11 .. 20) { struct S { // < this is line 9 int y; } auto s = S(i); } } The compiler says: test.d(9): Error: declaration S is already defined in another scope in main even though the respective scopes of the declarations are disjoint. IMO, this is a needless, arbitrary restriction. Worse yet, the compiles ICEs after this, so I filed a bug: https://issues.dlang.org/show_bug.cgi?id=18266 T -- Latin's a dead language, as dead as can be; it killed off all the Romans, and now it's killing me! -- Schoolboy
Re: Local static variables must have unique names within a function's scope.
On 1/19/18 1:11 PM, H. S. Teoh wrote: Fortunately this is not the case. However, the static variable case is annoying, and it's actually one case of a larger problem: void main() { foreach (i; 0 .. 10) { struct S { int x; } auto s = S(i); } foreach (i; 11 .. 20) { struct S { // < this is line 9 int y; } auto s = S(i); } } The compiler says: test.d(9): Error: declaration S is already defined in another scope in main even though the respective scopes of the declarations are disjoint. IMO, this is a needless, arbitrary restriction. Worse yet, the compiles ICEs after this, so I filed a bug: https://issues.dlang.org/show_bug.cgi?id=18266 Related: https://issues.dlang.org/show_bug.cgi?id=17653 -Steve
Re: Program exiting from thread with infinite loop
On Friday, 19 January 2018 at 18:18:31 UTC, Ali Çehreli wrote: On 01/19/2018 09:46 AM, Chris M. wrote: > I tried putting an infinite loop inside main() as well, didn't seem to > help. Another reason is an exception thrown in the child thread. If the exception is not caught, it will terminate the child thread and the main will not know anything about it. I have something about that here: http://ddili.org/ders/d.en/concurrency.html#ix_concurrency.exception,%20concurrency > I'm guessing there's probably a better way to make the main thread > wait? std.core.thread_joinAll is a way but you would want to tell the other thread to terminate first. https://dlang.org/phobos/core_thread.html#.thread_joinAll So, instead of while(true), try while(someCondition). In that case the main thread sets the condition e.g. by sending a message and then joins. Ali I'm not sure what's going on. I've tried all sorts of things from your link, it just runs the function once and exits every time. There aren't any exceptions being thrown from the thread. That robot example is basically exactly what I'm doing, and yet even that doesn't seem to resolve it.
Re: Program exiting from thread with infinite loop
On Friday, 19 January 2018 at 20:35:14 UTC, Chris M. wrote: On Friday, 19 January 2018 at 18:18:31 UTC, Ali Çehreli wrote: On 01/19/2018 09:46 AM, Chris M. wrote: > I tried putting an infinite loop inside main() as well, didn't seem to > help. Another reason is an exception thrown in the child thread. If the exception is not caught, it will terminate the child thread and the main will not know anything about it. I have something about that here: http://ddili.org/ders/d.en/concurrency.html#ix_concurrency.exception,%20concurrency > I'm guessing there's probably a better way to make the main thread > wait? std.core.thread_joinAll is a way but you would want to tell the other thread to terminate first. https://dlang.org/phobos/core_thread.html#.thread_joinAll So, instead of while(true), try while(someCondition). In that case the main thread sets the condition e.g. by sending a message and then joins. Ali I'm not sure what's going on. I've tried all sorts of things from your link, it just runs the function once and exits every time. There aren't any exceptions being thrown from the thread. That robot example is basically exactly what I'm doing, and yet even that doesn't seem to resolve it. What I tried import std.net.curl; import device; import std.datetime.systime; impor std.concurrency; void deviceDownloader() { auto APIServer = HTTP(); APIServer.addRequestHeader("X-Auth-Token:", AuthToken); APIServer.onProgress = delegate int(size_t dl, size_t dln, size_t ul, size_t uln) { if (dl != 0) write("Progress: downloaded ", dln, " of ", dl, "\r"); return 0; }; while (true) { auto currentTime = Clock.currTime; if (currentTime.minute % 5 == 0 && currentTime.second == 0) retrieveDevices(URL, APIServer); // info retrieved and stored here ownerTid.send("tmp"); } } void main() { spawn(&deviceDownloader); while (true) { auto msg = receiveOnly!string(); } }
Re: Program exiting from thread with infinite loop
On 1/19/18 12:05 PM, Chris M. wrote: I have the following that is supposed to pull and store info from a server every five minutes. It works if I move the body of deviceDownloader into main(). However when I try to spawn it in another thread it runs the function and then ends once it's done, like it's ignoring the while(true). I tried with std.parallelism, core.thread, vibe.d's concurrency library, but get the same result every time. Any idea how to better accomplish this? import std.net.curl; import device; import std.datetime.systime; impor std.concurrency; void deviceDownloader() { auto APIServer = HTTP(); APIServer.addRequestHeader("X-Auth-Token:", AuthToken); APIServer.onProgress = delegate int(size_t dl, size_t dln, size_t ul, size_t uln) { if (dl != 0) write("Progress: downloaded ", dln, " of ", dl, "\r"); What is this call doing? You aren't importing std.stdio, so it can't be D's normal write call. -Steve
Re: Program exiting from thread with infinite loop
On Friday, 19 January 2018 at 20:43:18 UTC, Steven Schveighoffer wrote: On 1/19/18 12:05 PM, Chris M. wrote: [...] What is this call doing? You aren't importing std.stdio, so it can't be D's normal write call. -Steve It is, left out the import on accident. I commented out the call to retrieveDevices, and now it's working, so at least I'm zoning in a bit. Appreciate all the help so far though.
Re: Program exiting from thread with infinite loop
On 1/19/18 3:54 PM, Chris M. wrote: On Friday, 19 January 2018 at 20:43:18 UTC, Steven Schveighoffer wrote: On 1/19/18 12:05 PM, Chris M. wrote: [...] What is this call doing? You aren't importing std.stdio, so it can't be D's normal write call. -Steve It is, left out the import on accident. I commented out the call to retrieveDevices, and now it's working, so at least I'm zoning in a bit. Appreciate all the help so far though. Hm... noticed you missed a 't' here as well: impor std.concurrency; It helps if you post actual working (or reproducing in any case) code. I've seen so many posts on this forum where people re-type their code in the post instead of copy-pasting, and then inadvertently leave out a major hint leading to the actual issue :) -Steve
Re: Program exiting from thread with infinite loop
On 01/19/2018 12:40 PM, Chris M. wrote: > it just runs the function once and exits every time. I would still put the following try+catch block around the whole logic: void deviceDownloader() { try { // ... existing contents of the function ... } catch (Exception exc) { writeln("Error: ", exc.msg); } catch (Error err) { writeln("Unrecoverable error: ", err.msg); } } Another thing to use it to start the program under a debugger and look at how many threads it has. If the program is called "deneme", on the console: gdb deneme Then, inside gdb: run Ctrl-C info threads That command lists two threads for me. Ali
Re: Program exiting from thread with infinite loop
On Friday, 19 January 2018 at 21:01:51 UTC, Steven Schveighoffer wrote: On 1/19/18 3:54 PM, Chris M. wrote: On Friday, 19 January 2018 at 20:43:18 UTC, Steven Schveighoffer wrote: On 1/19/18 12:05 PM, Chris M. wrote: [...] What is this call doing? You aren't importing std.stdio, so it can't be D's normal write call. -Steve It is, left out the import on accident. I commented out the call to retrieveDevices, and now it's working, so at least I'm zoning in a bit. Appreciate all the help so far though. Hm... noticed you missed a 't' here as well: impor std.concurrency; It helps if you post actual working (or reproducing in any case) code. I've seen so many posts on this forum where people re-type their code in the post instead of copy-pasting, and then inadvertently leave out a major hint leading to the actual issue :) -Steve Might have happened here. I left out two lines from main() that were for initializing a database because I didn't think they were relevant, then I realized the database was only being initialized in the main thread and not the one I was spawning. retrieveDevices() tried to access it and got a segfault (which I was ignoring because I was already getting a segfault from something else from before I put in threading). Should have been a red flag, but I moved the database initialization into the thread and it's working now.
Cannot initialize associative array
According to this (https://dlang.org/spec/hash-map.html#static_initialization) this is correct static initialization for AA: immutable RoundingMode[string] ibmRounding = [ ">" : RoundingMode.towardPositive, "<" : RoundingMode.towardNegative, "0" : RoundingMode.towardZero, "=0": RoundingMode.tiesToEven, "=^": RoundingMode.tiesToAway ]; Error: non-constant expression `[">":cast(RoundingMode)2, "<":cast(RoundingMode)3, "0":cast(RoundingMode)4, "=0":cast(RoundingMode)0, "=^":cast(RoundingMode)1]` RoundingMode is an enum.
Re: Cannot initialize associative array
On Friday, 19 January 2018 at 23:16:19 UTC, rumbu wrote: According to this (https://dlang.org/spec/hash-map.html#static_initialization) this is correct static initialization for AA: That only works inside a function, and, ironically, only if the variable is not `static`... I believe this is technically an implementation shortcoming - it is supposed to work in a static context too, but it isn't implemented. But regardless, right now, you need to do it in a function (or a static constructor) right now. You can separate declaration from initialization on module-level like so: immutable RoundingMode[string] ibmRounding; shared static this() { ibmRounding = [ ">" : RoundingMode.towardPositive, "<" : RoundingMode.towardNegative, "0" : RoundingMode.towardZero, "=0": RoundingMode.tiesToEven, "=^": RoundingMode.tiesToAway ]; }
Re: Cannot initialize associative array
On Friday, 19 January 2018 at 23:27:06 UTC, Adam D. Ruppe wrote: On Friday, 19 January 2018 at 23:16:19 UTC, rumbu wrote: According to this (https://dlang.org/spec/hash-map.html#static_initialization) this is correct static initialization for AA: That only works inside a function, and, ironically, only if the variable is not `static`... I believe this is technically an implementation shortcoming - it is supposed to work in a static context too, but it isn't implemented. But regardless, right now, you need to do it in a function (or a static constructor) right now. You can separate declaration from initialization on module-level like so: immutable RoundingMode[string] ibmRounding; shared static this() { ibmRounding = [ ">" : RoundingMode.towardPositive, "<" : RoundingMode.towardNegative, "0" : RoundingMode.towardZero, "=0": RoundingMode.tiesToEven, "=^": RoundingMode.tiesToAway ]; } Thank you Adam, just figured out myself the same solution, but I didn't expect to have a static constructor in main.d. I thought static constructors are meant to be used in imported modules. Thanks again.
Re: Local static variables must have unique names within a function's scope.
On Friday, January 19, 2018 10:11:36 H. S. Teoh via Digitalmars-d-learn wrote: > Fortunately this is not the case. However, the static variable case is > annoying, and it's actually one case of a larger problem: > > void main() { > foreach (i; 0 .. 10) { > struct S { > int x; > } > auto s = S(i); > } > foreach (i; 11 .. 20) { > struct S { // < this is line 9 > int y; > } > auto s = S(i); > } > } > > The compiler says: > > test.d(9): Error: declaration S is already defined in another scope in > main > > even though the respective scopes of the declarations are disjoint. IMO, > this is a needless, arbitrary restriction. Worse yet, the compiles ICEs > after this, so I filed a bug: > > https://issues.dlang.org/show_bug.cgi?id=18266 This limitation gets especially annoying when you start doing stuff like generating tests using static foreach. In those cases, any helper types or functions that you have can't be inside the static foreach. To an extent, you can get around it using a templates outside of the static foreach, but it's still annoying. - Jonathan M Davis
Re: Using Postgres connection functions
On Saturday, 13 January 2018 at 05:28:17 UTC, Joe wrote: Going beyond the connection, there are various other libpq functions that use a similar pattern of values passed using multiple parallel C arrays, e.g., PGresult *PQexecParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); Each of the `paramXxxxs' arguments are arrays (Oid is an alias for uint). [...] Focusing on the above function, suppose the first two parameter arrays are defined in a C program as: Oid paramTypes[] = {23, 25}; char *paramValues[] = {"1", "abcde"}; which could be expressed in D as: Oid [] paramTypes = [23, 25]; string [] paramValues = ["1", "abcde"]; I know the paramTypes could be passed as null, letting PG deduce the data types but suppose we have some reason to accumulate types, etc., in D slices. I know the paramValues can be manipulated in a manner similar to the one shown in my first post, namely something like this: extern(C) char * [2] pvs; foreach (i, val; paramValues) pvs[i] = cast(char *)toStringz(val); And then use "cast(const char **)pvs" for the paramValues argument. The only feedback that I received that was explicit to this approach was in response to my initial post, in which Adam D. Ruppe said that what I did was "decent". So I have two lingering doubts: 1. Is malloc() the only way to allocate the arrays, either of Oid's, int's or char *'s, for passing to the libpq functions? IOW, isn't there a way to take advantage of D's 'new' (and thus the GC)? 2. How to convert a slice of Oid's or int's to an array of pointers suitable by processing by the libpq C function? A technique similar to the previous one seems to work, e.g., extern(C) Oid [2] pts; foreach (i, typ; paramTypes) pts[i] = typ; But I'm not sure if it's really working (when I mistakenly had a * in the pts declaration, at one point it also seemed to work).
Re: Using Postgres connection functions
On Saturday, 20 January 2018 at 04:09:01 UTC, Joe wrote: extern(C) char * [2] pvs; foreach (i, val; paramValues) pvs[i] = cast(char *)toStringz(val); And then use "cast(const char **)pvs" for the paramValues argument. A slight improvement here that removes the need for any casts (and the extern(C) is useless here btw) is to just define it as const(char)*: const(char) * [2] pvs; foreach (i, val; paramValues) pvs[i] = toStringz(val); Then you can call the argument with plain `pvs.ptr` instead of casting it. Though, make sure you remember the null at the end too! 1. Is malloc() the only way to allocate the arrays, either of Oid's, int's or char *'s, for passing to the libpq functions? IOW, isn't there a way to take advantage of D's 'new' (and thus the GC)? const(char)*[] pvs = new const(char)*[](size_here); // could also have been `auto pvs = ...;` btw // then still pass it to pqFunc(pvs.ptr) // the .ptr gets the char** out of it. Just double check the documentation of any C function you pass it to to make sure it doesn't explicitly say you must malloc it. Some C functions will try to free() the pointer you pass it, or may hold on to it. D's GC can't see pointers C functions keep, so it might try to free that array any time after the local variable `pvs` in D goes out of scope. 2. How to convert a slice of Oid's or int's to an array of pointers suitable by processing by the libpq C function? Same as above. The general pattern is: C_Type[] name = new C_Type[](requested_size); // pass as `name.ptr`. This becomes a C_Type* Just again, remember requested_size needs to include the null terminator when C requires it, so a +1 might be helpful. And also, no need for extern(C). That's more for function declarations/pointers or maybe global variables C needs to be able to see. But I'm not sure if it's really working (when I mistakenly had a * in the pts declaration, at one point it also seemed to work). Oh yikes, that would have been undefined behavior there. So [x] on a pointer will just access memory past it - just like in C - and might sometimes work, might sometimes overwrite other memory (in your case, it probably overwrote some other local variable on the stack), or, best case scenario really, might cause a segmentation fault or access violation.