Re: Member variables in method are null when called as delegate from thread
On Wednesday, 13 January 2021 at 02:15:49 UTC, Tim wrote: Basically, the program calls a function which modifies a document in the database. If it is called form it's own class' constructor, it works fine. If it is called by a thread, it never returns. ... class Caller : Thread{ void delegate() mFunc; this(void delegate() func){ mFunc = func; super(&loop); start(); } void loop(){ while(true){ mFunc(); } } } class Callable{ MongoClient db; Caller caller; this(){ db = connectMongoDB("127.0.0.1"); foo(); caller = new Caller(&foo); } ~this(){ db.cleanupConnections(); } void foo(){ writeln("Started"); auto result = db.getCollection("test.collection").findAndModify([ "state": "running"], ["$set": ["state": "stopped"] ]); writeln(result); writeln("Finished"); } } Note that if you are trying to debug a crash or hang of a program by printing messages to the console, you need to flush stdout multiple times in the vicinity of the problem, otherwise stdio's buffering may make it appear as though the program crashed or hung significantly earlier than it really did. (This is not a merely theoretical problem; I trip over it frequently myself.) Anyway, I think your real problem is that MongoClient is not thread-safe. From the official vibe.d documentation (https://vibed.org/api/vibe.db.mongo.mongo/connectMongoDB): Note that the returned MongoClient uses a vibe.core.connectionpool.ConnectionPool internally to create and reuse connections as necessary. Thus, the MongoClient instance can - and should - be shared among all fibers in a thread by storing in in a thread local variable. Note the "in a thread" part; you may only use a connection from the same thread that opened it. (Why? I'm not familiar with vibe.d's API or code base, so I don't really know. But, I'd guess that the connection reuse mechanism mentioned in the docs requires some of the information that you might expect to be stored in the MongoClient instance itself to instead end up in thread-local storage (whether native or emulated). Or, there may simply be a manual "same thread" check built into the DB operations to prevent data races, and the error message isn't reaching you for some reason. `assert` messages don't print in release mode, and I've found the gdb debugger for D quite unreliable when trying to inspect multi-threaded code.) Try moving the calls to `connectMongoDB` and `cleanupConnections` into the same thread as `foo`. (I can't think of a good reason to be doing these in the original thread, other than convenience.) If you want to loop in multiple threads simultaneously, just open a separate connection per thread, like the vibe.d docs suggest.
Re: Anything in D to avoid check for null everywhere?
Currently I'm with this: auto ref ifNotNull(T, T2)(T lhs, lazy T2 rhs) { if(lhs) { rhs(); } return lhs; } far from good. I wish there was a way to create a new operator so I would make .? similar to C#'s but would evaluate the left-handed side only if it's null and do nothing otherwise (C#'s evaluate to null, probably due to lack of control of flow structure, which isn't possible within a source code, only from compiler's side, as far i know)
Re: Member variables in method are null when called as delegate from thread
On Tuesday, 12 January 2021 at 01:49:11 UTC, tsbockman wrote: The compiler and the physical CPU are both allowed to change the order in which instructions are executed to something different from what your code specifies, as long as the visible, "official" results and effects of the chosen order of execution are the same as those of your specified code, FROM THE PERSPECTIVE OF THE EXECUTING THREAD. This is allowed so that the compiler can optimize to minimize negative "unofficial" effects such as the passage of time and memory consumption. However, this re-ordering IS permitted to freely alter the behavior of your code from the perspective of OTHER threads. A likely cause of your bug is that the write to db by the constructor's thread is being committed to memory after the read of db by the MessageService thread. In order to RELIABLY fix this kind of problem, you must correctly use the only commands which the compiler and CPU are NOT allowed to reorder with respect to other threads, namely atomic operations, memory barriers and synchronization primitives. A wide selection of these tools may be found in these D runtime library modules: core.sync: http://dpldocs.info/experimental-docs/core.sync.html core.atomic: http://dpldocs.info/experimental-docs/core.atomic.html core.thread: http://dpldocs.info/experimental-docs/core.thread.html (I recommend using Adam D. Ruppe's unofficial but superior rendering of the D runtime documentation at dpldocs.info rather than the official dlang.org rendering, as I found some necessary pieces of the documentation are just mysteriously missing from the offical version.) Be warned that most models of multi-threaded programming are difficult to implement correctly, as opposed to ALMOST correctly with subtle heisen-bugs. You should either stick to one of the known simple models like immutable message passing with GC, or do some studying before writing too much code. Here are some resources which I have found very helpful in learning to understand this topic, and to avoid its pitfalls: Short educational game: https://deadlockempire.github.io/ Tech talk by C++ expert Herb Sutter (D's core.atomic uses the C++ memory model): https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2 https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2 If you want to seriously dig into this, I suggest reviewing some or all of the content at the links above. If you're still confused about how to apply it in D, feel free to come back and ask for examples or code reviews. I'd rather not start with examples, though, because if you don't understand the rules and principles behind them, it's really easy to unknowingly introduce bugs into otherwise correct examples with seemingly innocent changes. Fantastic response, thank you! I did some more digging and properly narrowed down where the issue is and created a test script that demonstrates the problem. Let me know what you think and if it could still be a similar problem to what you have stated above. I'll still read that info you sent to sharpen up on these concepts. Basically, the program calls a function which modifies a document in the database. If it is called form it's own class' constructor, it works fine. If it is called by a thread, it never returns. I don't think that a member variable is going null or anything. But a strange problem that I can't seem to debug. The output is at the bottom. import vibe.db.mongo.mongo; import core.thread; import std.stdio; void main(){ auto callable = new Callable(); while(true){} } class Caller : Thread{ void delegate() mFunc; this(void delegate() func){ mFunc = func; super(&loop); start(); } void loop(){ while(true){ mFunc(); } } } class Callable{ MongoClient db; Caller caller; this(){ db = connectMongoDB("127.0.0.1"); foo(); caller = new Caller(&foo); } ~this(){ db.cleanupConnections(); } void foo(){ writeln("Started"); auto result = db.getCollection("test.collection").findAndModify([ "state": "running"], ["$set": ["state": "stopped"] ]); writeln(result); writeln("Finished"); } } Output: Started {"_id":"5ff6705e21e91678c737533f","state":"running","knowledge":true} Finished Started
Re: Developing and running D GUI app on Android
On Sun, Jan 10, 2021 at 06:58:13PM +, aberba via Digitalmars-d-learn wrote: > I'm looking to explore running a D application on Android based on > Adams previous foundation work. However, I'm not familiar with the > Android + D integration so I need some help. > > Has any of you successfully done that? Could use a sample code or > anything I can use to figure out how to start. First, you need a way to build an APK, and then transfer that to your Android device for testing. Building an APK *can* be done manually (well, scripted), but I don't recommend it. The simplest way is probably to install Android Studio and the Android SDK, and use Gradle to build your project. Gradle takes care of the finicky details of how to build an APK, and the Android dev tools let you install to Android in debug mode without having to find your own way of transferring APKs. For compiling D, you'll need LDC configured to cross-compile to Android: https://wiki.dlang.org/Build_D_for_Android Talk to Adam for more details -- he has done some work to remove some of the manual munging described on that page, but I don't remember how much. For maximum convenience, you probably want to figure out how to integrate your build process with Gradle so that it can be done with a single command. (I opted not to use Gradle, but an SCons-based system that's actually very fast at cross-compiling D and building APKs. But most people will probably want to use Gradle.) Most of the hard work is the setup; once you have a working environment writing D for Android is pretty smooth. Esp. with Adam's jni.d, interacting with Android's Java APIs ought to be a lot easier than ever. If you have more specific questions I can try to answer them. T -- If it's green, it's biology, If it stinks, it's chemistry, If it has numbers it's math, If it doesn't work, it's technology.
Re: Problem with templated alias as delegate parameter type
On Tuesday, 12 January 2021 at 21:32:14 UTC, Ali Çehreli wrote: On 1/12/21 12:58 PM, cc wrote: > void send(T query, void delegate(T.RESPONSE) callback) { That wants a delegate that takes a T.RESPONSE (PingResponse in this case). However, the following lambda is in fact a template: > send(PingQuery("helo"), (resp) { You specify the type there and it works: send(PingQuery("helo"), (PingResponse resp) { Ali That seems to work, thanks. I ended up having to define a second template parameter: template send(T,TR) if (is(TR == T.RESPONSE)) { void send(T query, void delegate(TR) callback) { ...
Re: I want to create my own Tuple type
On Tuesday, 12 January 2021 at 21:38:59 UTC, sighoya wrote: What about this? No magic, but I don't know the performance impact. ``` import std.meta; import std.conv; template same(Types...) { static if (Types.length >= 2) { static if (is(Types[0] == Types[$ - 1])) { const same = same!(Types[1 .. $]); } else { enum bool same = false; } } else { enum bool same = true; } } I also like the recursive version better. I borrowed the core concept from Phobos. I assume they don't use recursion because they are afraid of running out of stack space? Or maybe it is because of performance? struct Tuple(Types...) { static if (same!Types) { public Types[0][Types.length] elements; Yes, this is what I also felt was the right approach. But then I realized that AliasSeq (which is what you get if you use "Types expand") is hardwired in the compiler in a hackish way so that you get various features from it, like implicit splatting (expanding the sequence into arguments)? That kinda makes it difficult to get the right semantics as I know of no way to do it without AliasSeq, but maybe there is some way, perhaps one can convert it into an AliasSeq somehow. I kinda don't like this kind of compiler-magic for one specific type as it limits what you can do, but I guess it was done for easy-of-implementation. static foreach (int i, T; Types) { mixin("public " ~ T.stringof ~ " " ~ "elem" ~ i.stringof ~ ";"); } Yep, I had this version at some point :-) I think the way you approached it is the intuitive way, but the problem is really that AliasSeq get special treatment by the compiler so it is currently difficult to work around it? One should probably look closer at the language semantics and try to come up with a more generic mechanism as that would make for more powerful meta programming.
Re: Member variables in method are null when called as delegate from thread
On Tuesday, 12 January 2021 at 14:00:11 UTC, Steven Schveighoffer wrote: On 1/11/21 8:49 PM, tsbockman wrote: However, this re-ordering IS permitted to freely alter the behavior of your code from the perspective of OTHER threads. A likely cause of your bug is that the write to db by the constructor's thread is being committed to memory after the read of db by the MessageService thread. I don't think this is valid. You might be right, but your analysis below assumes the answers to a number of questions which aren't answered in the source code provided by the OP. Perhaps you are familiar with the implementations of the APIs in question, but I'm not and thought it unwise to assume too much, given that the whole reason we're having this discussion is that the code doesn't actually work... Regardless, the simple way to find out if I'm on the right track or not is just to protect access to Foo's fields with a mutex and see if that fixes the problem. If it does, then either it's a memory ordering issue like I suggested (or a code gen bug), and the mutex can be replaced with something more efficient if necessary. 1. the compiler MUST NOT reorder the storage of db to after you pass a delegate into an opaque function (array allocation). Is the function actually opaque, though? If the source code is available to the compiler for inlining (or maybe if it's marked `pure`?) then reordering is still allowed. 2. The CPU is not going to reorder, because the memory allocation is going to take a global lock anyway (mutex locks should ensure memory consistency). This is not a safe assumption. It is quite easy to design a thread-safe allocator that does not take a global lock for every allocation, and indeed *necessary* if you want it to scale well to heavy loads on high core count systems. Even if that's how it works today, I wouldn't write code that depends on this behavior, unless the language standard formally guaranteed it, because someone will change it sooner or later as core counts continue to climb. I can't ever imagine creating a thread (which is likely what MessageService ctor is doing) to not have a consistent memory with the creating thread on construction. It seems reasonable to assume that thread creation includes a write barrier somewhere, but what if MessageService is using an existing thread pool? The CPU would have to go out of its way to make it inconsistent. No, there are many levels of caching involved in the system, most of which are not shared by all cores. The CPU has to go out of its way to make memory appear consistent between cores, and this is expensive enough that it doesn't do so by default. That's why atomics and memory barriers exist, to tell the CPU to go out of its way to make things consistent. You often don't have to deal with these issues directly when using higher-level multi-threading APIs, but that's because they try to include the appropriate atomics/barriers internally, not because the CPU has to "go out of its way" to make things inconsistent.
Re: I want to create my own Tuple type
What about this? No magic, but I don't know the performance impact. ``` import std.meta; import std.conv; template same(Types...) { static if (Types.length >= 2) { static if (is(Types[0] == Types[$ - 1])) { const same = same!(Types[1 .. $]); } else { enum bool same = false; } } else { enum bool same = true; } } struct Tuple(Types...) { static if (same!Types) { public Types[0][Types.length] elements; public this(Types[0][Types.length] elements...) { this.elements = elements; } } else { static foreach (int i, T; Types) { mixin("public " ~ T.stringof ~ " " ~ "elem" ~ i.stringof ~ ";"); } public this(Types elements) { static foreach (int i, T; Types) { mixin("this.elem" ~ i.stringof ~ "=" ~ "elements[i]" ~ ";"); } } } } int main() { import std.stdio; auto homogenousTuple = Tuple!(int, int)(2, 3); writeln("homogenous tuple ", homogenousTuple.elements[0], ":", typeid(homogenousTuple.elements[0]), ":", homogenousTuple.elements[1], ":", typeid(homogenousTuple.elements[1])); auto heterogenousTuple = Tuple!(int, float)(2, 3); writeln("heterogenous tuple ", heterogenousTuple.elem0, ":", typeid(heterogenousTuple.elem0), ":", heterogenousTuple.elem1, ":", typeid(heterogenousTuple.elem1)); return 0; } ``` Problem is, the type arguments getn't inferred.
Anything in D to avoid check for null everywhere?
I was looking for a way to avoid null checks everywhere. I was checking the Null object pattern, or use something like enforce pattern, or even if I could make a new operator and implement something like C#'s .? operator, that Java was going to have one but they refused[1] (doesn't behave exactly as C#'s actually), Kotlin also got something in this area[2] What some D ways to avoid those checks? [1]: https://mail.openjdk.java.net/pipermail/coin-dev/2009-March/47.html [2]: https://kotlinlang.org/docs/reference/null-safety.html#safe-calls
Re: Problem with templated alias as delegate parameter type
On 1/12/21 12:58 PM, cc wrote: > void send(T query, void delegate(T.RESPONSE) callback) { That wants a delegate that takes a T.RESPONSE (PingResponse in this case). However, the following lambda is in fact a template: > send(PingQuery("helo"), (resp) { You specify the type there and it works: send(PingQuery("helo"), (PingResponse resp) { Ali
Re: properly passing strings to functions? (C++ vs D)
On Tuesday, 12 January 2021 at 18:12:14 UTC, Q. Schroll wrote: Did you consider `in`? It will do that in some time and do it now with -preview=in. If you're using `const`, in almost all cases, `in` will work, too, and be better (and shorter). Has the redesignation of "in" like in the preview been formally accepted as a part of language? I know that it was suggested to make "in" the optimized parameter passing for const which I like. However, if I'm going to use it I need to know if this going to be accepted as I don't want go around and change all the parameters back again if it was not accepted.
Problem with templated alias as delegate parameter type
Given the following program: struct PingQuery { string msg; } struct PingResponse { string msg; } template send(T) { void send(T query, void delegate(PingResponse) callback) { writefln("Sending: %s", query); if (callback) { PingResponse resp; resp.msg = query.msg; callback(resp); } } } void main() { send(PingQuery("helo"), (resp) { writefln("Got response: %s", resp); }); } This works, but as you can see the PingResponse struct is hardcoded in the send function. If I try to make it a part of the template in a way such as this: struct PingQuery { alias RESPONSE = PingResponse; string msg; } struct PingResponse { string msg; } template send(T) { static assert(is(T.RESPONSE == PingQuery.RESPONSE)); // this succeeds at least void send(T query, void delegate(T.RESPONSE) callback) { writefln("Sending: %s", query); if (callback) { T.RESPONSE resp; resp.msg = query.msg; callback(resp); } } } void main() { send(PingQuery("helo"), (resp) { writefln("Got response: %s", resp); }); } I get: delegatetest.d(48): Error: template `delegatetest.send` cannot deduce function from argument types `!()(PingQuery, void)`, candidates are: delegatetest.d(35):`send(T)(T query, void delegate(T.RESPONSE) callback)` Same error if I use a nested struct (e.g. struct PingQuery { struct RESPONSE {} }) instead of an alias. Currently using DMD32 D Compiler v2.095.0-dirty (win64).
Re: Variadic Struct Parameter
On 1/12/21 2:49 PM, ryuukk_ wrote: On Tuesday, 12 January 2021 at 18:44:53 UTC, Jonathan Levi wrote: On Tuesday, 12 January 2021 at 17:46:14 UTC, Q. Schroll wrote: It's obvious why arrays work, it's the primary use case. I have no idea why classes are allowed. That classes are allowed, but structs are not, makes no sense to me. I like the variadic feature for classes, but I wish it worked for structs as well, given that structs are value types on the stack anyway, the same assembly could have either signature (assuming matching argument/struct ordering). But why does this compile? ``` struct S {/*...*/} void fun(S s...) {/*...*/} ``` If structs do not work as variadic parameters, why does `fun` still compile? you can do this: ``` import std.stdio; import core.internal.moving; import core.memory; void main() { auto a = Data(1); auto b = Data(2); auto c = Data(3); hello(a, b, c); } void hello(Data...)(Data args) this is a template parameter named 'Data' that supersedes the module-level type named 'Data'. Not the same thing. -Steve
Re: Renamed but non-selective import?
On Tuesday, 12 January 2021 at 20:19:20 UTC, ag0aep6g wrote: On 12.01.21 21:09, cc wrote: import core.sys.windows.windows; import mymodule; // contains a struct named MSG Error: `core.sys.windows.winuser.MSG` ... conflicts with `mymodule.MSG` vs import core.sys.windows.windows : winMSG = MSG; // this leaves out other symbols Error: undefined identifier `HWND` Error: undefined identifier `LPCSTR` import core.sys.windows.windows; import mymodule; alias MSG = mymodule.MSG; alias winMSG = core.sys.windows.windows.MSG; Ahh simple enough, thanks.
Re: Variadic Struct Parameter
On 1/12/21 12:46 PM, Q. Schroll wrote: On Tuesday, 12 January 2021 at 17:26:15 UTC, Jonathan Levi wrote: Why is this not working? ``` struct S { int x; string y; } void fun(S s ...) { This is intended for arrays and classes, not structs. Using ... for something other than arrays and c fun(S(5,"hi")); That one should compile... fun(5,"hi"); and the second one not. It's obvious why arrays work, it's the primary use case. I have no idea why classes are allowed. That classes are allowed, but structs are not, makes no sense to me. Originally, structs did not allow a constructor. I'm thinking probably when they got constructors, the (almost never-used) variadic form of class parameter passing did not get ported to structs. -Steve
Re: Variadic Struct Parameter
On Tuesday, 12 January 2021 at 18:44:53 UTC, Jonathan Levi wrote: On Tuesday, 12 January 2021 at 17:46:14 UTC, Q. Schroll wrote: It's obvious why arrays work, it's the primary use case. I have no idea why classes are allowed. That classes are allowed, but structs are not, makes no sense to me. I like the variadic feature for classes, but I wish it worked for structs as well, given that structs are value types on the stack anyway, the same assembly could have either signature (assuming matching argument/struct ordering). But why does this compile? ``` struct S {/*...*/} void fun(S s...) {/*...*/} ``` If structs do not work as variadic parameters, why does `fun` still compile? Because D does allow you to specify things that have no effect. People sometimes complain about this as nonsense, but it has its merits in meta-programming: void fun(T)(T t...) { } Here, if T is a class or array type (including static arrays, btw), the dots have an effect, otherwise not. It would be unnecessary to require a split on the basis what T is.
Re: Renamed but non-selective import?
On 12.01.21 21:09, cc wrote: import core.sys.windows.windows; import mymodule; // contains a struct named MSG Error: `core.sys.windows.winuser.MSG` ... conflicts with `mymodule.MSG` vs import core.sys.windows.windows : winMSG = MSG; // this leaves out other symbols Error: undefined identifier `HWND` Error: undefined identifier `LPCSTR` import core.sys.windows.windows; import mymodule; alias MSG = mymodule.MSG; alias winMSG = core.sys.windows.windows.MSG;
Renamed but non-selective import?
Is it possible to import all symbols of a module, while renaming just one of them? It seems like doing an import with renaming automatically makes it selective. In the example below, I'd prefer not to have to use the fully qualified name for mymodule.MSG every time e.g.: import core.sys.windows.windows; import mymodule; // contains a struct named MSG Error: `core.sys.windows.winuser.MSG` ... conflicts with `mymodule.MSG` vs import core.sys.windows.windows : winMSG = MSG; // this leaves out other symbols Error: undefined identifier `HWND` Error: undefined identifier `LPCSTR`
Re: Variadic Struct Parameter
On Tuesday, 12 January 2021 at 18:44:53 UTC, Jonathan Levi wrote: On Tuesday, 12 January 2021 at 17:46:14 UTC, Q. Schroll wrote: It's obvious why arrays work, it's the primary use case. I have no idea why classes are allowed. That classes are allowed, but structs are not, makes no sense to me. I like the variadic feature for classes, but I wish it worked for structs as well, given that structs are value types on the stack anyway, the same assembly could have either signature (assuming matching argument/struct ordering). But why does this compile? ``` struct S {/*...*/} void fun(S s...) {/*...*/} ``` If structs do not work as variadic parameters, why does `fun` still compile? you can do this: ``` import std.stdio; import core.internal.moving; import core.memory; void main() { auto a = Data(1); auto b = Data(2); auto c = Data(3); hello(a, b, c); } void hello(Data...)(Data args) { writeln("n: ", args.length); foreach (data; args) writeln(data); } struct Data { int a = 5; } ``` this works fine: https://run.dlang.io/is/YA9syo
Re: Variadic Struct Parameter
On 1/12/21 10:44 AM, Jonathan Levi wrote: > why does `fun` still compile? I'm not familiar with that particular syntax, I don't know why it compiles, and I don't know why structs are different. :) However, it looks very much like the following *slice* syntax: void fun(S[] s...) { writeln(s); } In that case, the function receives a slice (to an array on the stack; so, do not keep a reference to it). Is that what you want? Ali
Re: Variadic Struct Parameter
On Tuesday, 12 January 2021 at 17:46:14 UTC, Q. Schroll wrote: It's obvious why arrays work, it's the primary use case. I have no idea why classes are allowed. That classes are allowed, but structs are not, makes no sense to me. I like the variadic feature for classes, but I wish it worked for structs as well, given that structs are value types on the stack anyway, the same assembly could have either signature (assuming matching argument/struct ordering). But why does this compile? ``` struct S {/*...*/} void fun(S s...) {/*...*/} ``` If structs do not work as variadic parameters, why does `fun` still compile?
Re: properly passing strings to functions? (C++ vs D)
On Monday, 11 January 2021 at 16:53:50 UTC, IGotD- wrote: I usually use "const string text" because D has no implicit declaration of variables. So using "ref" will not create a variable. This is contrary to C++ where passing as "const std::string &text" has a performance benefit and also C++ creates a unnamed variable for you. Did you consider `in`? It will do that in some time and do it now with -preview=in. If you're using `const`, in almost all cases, `in` will work, too, and be better (and shorter).
Re: properly passing strings to functions? (C++ vs D)
On Monday, 11 January 2021 at 14:12:57 UTC, zack wrote: A beginner question: How to pass strings properly to functions in D? Is there any allocation going on if just use a function as "myPrint"? In C++ I have often seen calls where one just passes a reference/const reference to a string to avoid allocation. C++: void myPrintCPP(const std::string& input){ ... } D: void myPrint(string text){ ... } void myPrintRef(ref string text) { ... } In D, `string` is an abbreviation for the type immutable(char)[], i.e. slice of immutable char. The slice type is a pointer+length pair, a (T*, size_t) tuple, it is very lightweight. Using `ref T[]` (that includes `ref string` aka `ref immutable(char)[]` is the way if you want reassignments or expanding/shrinking of the array to be visible to the caller. Since the cost of copying a pointer and a length is very low, I'd just use this: void myPrint(string text) { ... } It'll be probably what you want. Since you cannot write the immutable characters, if you don't intend to reassign, expand, or shrink the string locally, you can use `in string text`. You can basically only read `in` parameters for information. What `in` buys you is that the compiler will figure out the best way to pass the object. C++'s const T& will reference always, which is worse than a copy for small types. D's `in` will copy if the compiler thinks it's cheaper than referencing. Give https://dlang.org/changelog/2.094.0.html#preview-in a read, if you want details about `in`. Use it when it applies. It also documents intent.
Re: Variadic Struct Parameter
On Tuesday, 12 January 2021 at 17:26:15 UTC, Jonathan Levi wrote: Why is this not working? ``` struct S { int x; string y; } void fun(S s ...) { This is intended for arrays and classes, not structs. Using ... for something other than arrays and c fun(S(5,"hi")); That one should compile... fun(5,"hi"); and the second one not. It's obvious why arrays work, it's the primary use case. I have no idea why classes are allowed. That classes are allowed, but structs are not, makes no sense to me.
Variadic Struct Parameter
Why is this not working? ``` struct S { int x; string y; } void fun(S s ...) { writeln(s); } void main() { fun(S(5,"hi")); fun(5,"hi"); } ``` Why does `fun` compile if calling it does not?
Re: any chance to get it working on windows xp?
On Tuesday, 12 January 2021 at 13:51:16 UTC, Imperatorn wrote: On Tuesday, 12 January 2021 at 12:40:28 UTC, Mike Parker wrote: Are you asking if anyone patched the binaries and made them available as a third-party download? Yes, or if there are any plans for those changes to go upstream. I'm unaware of anyone who has done that. And I wouldn't expect that sort of thing to make it upstream.
Re: Member variables in method are null when called as delegate from thread
On 1/11/21 8:49 PM, tsbockman wrote: On Monday, 11 January 2021 at 00:43:00 UTC, Tim wrote: When MessageService calls the delegate for start, db is null. If I call start() in the Foo constructor it works just fine. Am I missing something here? Do delegates get called outside of their class context? I know I could just pass the db into start but I want to work out exactly why this is happening The compiler and the physical CPU are both allowed to change the order in which instructions are executed to something different from what your code specifies, as long as the visible, "official" results and effects of the chosen order of execution are the same as those of your specified code, FROM THE PERSPECTIVE OF THE EXECUTING THREAD. This is allowed so that the compiler can optimize to minimize negative "unofficial" effects such as the passage of time and memory consumption. However, this re-ordering IS permitted to freely alter the behavior of your code from the perspective of OTHER threads. A likely cause of your bug is that the write to db by the constructor's thread is being committed to memory after the read of db by the MessageService thread. I don't think this is valid. 1. the compiler MUST NOT reorder the storage of db to after you pass a delegate into an opaque function (array allocation). 2. The CPU is not going to reorder, because the memory allocation is going to take a global lock anyway (mutex locks should ensure memory consistency). I think something weird is going on, but I don't know what. In order to RELIABLY fix this kind of problem, you must correctly use the only commands which the compiler and CPU are NOT allowed to reorder with respect to other threads, namely atomic operations, memory barriers and synchronization primitives. I can't ever imagine creating a thread (which is likely what MessageService ctor is doing) to not have a consistent memory with the creating thread on construction. Why would the other thread not see the same memory when it didn't exist before? The CPU would have to go out of its way to make it inconsistent. -Steve
Re: Member variables in method are null when called as delegate from thread
On 1/11/21 12:26 PM, Arafel wrote: Thanks for the detailed explanation! I think this mixing of types and storage classes makes a very unfortunate combination: ``` import std; int i = 0; shared int j = 0; struct S { int i = 0; shared int j = 0; } S s; void main() { i = 1; j = 1; s.i = 1; s.j = 1; spawn(&f); } void f() { assert(i == 0); // Expected assert(j == 1); // Expected assert(s.i == 0); // Expected assert(s.j == 0); // Wait, what? } ``` I agree that once you know the inner workings it makes sense, but a naïve approach might suggest that `s.j` would be... well, shared, just like `j`. It's definitely confusing, if you don't know what shared means in all contexts. shared as storage -> put in the shared globals shared as type -> the thing can be shared between threads. The second meaning does not mean it's automatically shared, just that it's shareable. -Steve
Re: any chance to get it working on windows xp?
On Tuesday, 12 January 2021 at 12:40:28 UTC, Mike Parker wrote: On Tuesday, 12 January 2021 at 10:25:42 UTC, Imperatorn wrote: https://forum.dlang.org/post/qsgtohsykwldipgng...@forum.dlang.org On Saturday, 3 October 2020 at 23:14:57 UTC, Drone1h wrote: On Monday, 18 May 2020 at 05:36:01 UTC, Mike Parker wrote: [...] This is not exactly a reply to the original thread, but maybe it helps someone who has searched for "Windows XP" in the forum and found this discussion. [...] Anyone knows if these changes where ever made? Are you asking if anyone patched the binaries and made them available as a third-party download? Yes, or if there are any plans for those changes to go upstream.
Re: Member variables in method are null when called as delegate from thread
On 1/11/21 6:52 PM, Paul Backus wrote: On Monday, 11 January 2021 at 16:10:49 UTC, Steven Schveighoffer wrote: There are some... odd rules. struct S { [...] immutable int e = 5; // stored in data segment, not per instance! Are you sure? struct S { immutable int n = 123; this(int n) { this.n = n; } } void main() { S s1; S s2 = 456; assert(s1.n == 123); assert(s2.n == 456); } Yes, I was sure, but clearly wrong ;) Hm... I guess it was changed! Deprecated in 2.065 [1] and finally changed in 2.067 [2] Now you need static immutable to make it not part of the instance. Which makes sense (score 1 for consistency!) -Steve [1] https://dlang.org/changelog/2.065.0.html#staticfields2 [2] https://issues.dlang.org/show_bug.cgi?id=3449
Re: any chance to get it working on windows xp?
On Tuesday, 12 January 2021 at 10:25:42 UTC, Imperatorn wrote: https://forum.dlang.org/post/qsgtohsykwldipgng...@forum.dlang.org On Saturday, 3 October 2020 at 23:14:57 UTC, Drone1h wrote: On Monday, 18 May 2020 at 05:36:01 UTC, Mike Parker wrote: [...] This is not exactly a reply to the original thread, but maybe it helps someone who has searched for "Windows XP" in the forum and found this discussion. [...] Anyone knows if these changes where ever made? Are you asking if anyone patched the binaries and made them available as a third-party download?
Re: I want to create my own Tuple type
Ok, so I now have this, but I think maybe the switch could be turned into a static array by an reinterpret cast of "&expand[0]"? I would assume the layout would typically be "expand_field_0, expand_field_1 etc... template Tuple(Types...){ template same(){ static foreach (i, dummy; Types) { static if (i + 1 < Types.length && !is(typeof(same) == bool) && !is(Types[i] == Types[i + 1])) { enum bool same = false; } } static if (!is(typeof(same) == bool)) { enum bool same = true; } } struct Tuple { Types expand; alias expand this; static if (same!()) { auto opIndex(size_t i) { switch (i) { static foreach (j; 0 .. Types.length) { case j: return this.expand[j]; } default: assert(0); } } } } }
Re: Static constructor
NOTE : the entire code we are talking about is in the tiny url in my previous post. On Thursday, 7 January 2021 at 01:55:07 UTC, SealabJaster wrote: On Wednesday, 6 January 2021 at 17:05:02 UTC, ludo wrote: ... Using a static class like this seems to mostly be a design decision. So in otherwords, this class is essentially being used as a unique namespace for all of the other functions. Another way to look at it is just a singleton without a `.instance` getter. Ok, I agree that ends up being a kind of strange singleton. But yes it was D v1 code. Do we agree that the following multi-threaded singleton pattern is the proper way as of today, instead of this static functions in a non static class (in multithreaded environment)? shared(T) singleton() { static shared T instance; if(!instance) { synchronized { if(!instance) instance = new shared(T)(); } } return instance; } --- As for some of the other stuff, Associative Array literals in D can't actually be used at compile-time (at least, last time I tried), so they have to be created inside of the static constructor. OK, I found https://dlang.org/spec/hash-map.html#static_initialization Quote from that doc: "Static Initialization of AAs NOTE: Not yet implemented. " If I understand, as of today an AA init depends on a runtime function for historical reasons. A bit weird for an array indeed perfectly known at compile time, but someday some core language contributor will have a look at it, I guess. Next is the mutex. `Object` is the base class that every class in D will implicitly inherit from, like in C# for example. Object has a `.monitor` field which is basically just a mutex, so is used with multi-threading synchronisation. I find it a bit odd that they're just returning an object instead of a Mutex (module core.sync.mutex), but I'm sure there's a reason why. If we consider the class from my first post, the comment coming with the getMutex func is following in the original code that I am "cleaning-up": "Get an OpenAL mutex to ensure that no two threads ever execute OpenAL functionality simultaneously." But the OpenAL class only has one function (anotherFunc), and as you say SealabJaster, it looks odd to use this Object mutex. I see two options to replace this mutex thing: * make the entire class synchronized (writing "synchronized class OpenAL") * make the anotherFunc function synchronized. So just one keyword to add! If I understand well, this will accomplish the goal quoted with no further comestics needed! Only one keyword over explicitely using object mutex. Am I right? Thanks
any chance to get it working on windows xp?
https://forum.dlang.org/post/qsgtohsykwldipgng...@forum.dlang.org On Saturday, 3 October 2020 at 23:14:57 UTC, Drone1h wrote: On Monday, 18 May 2020 at 05:36:01 UTC, Mike Parker wrote: [...] This is not exactly a reply to the original thread, but maybe it helps someone who has searched for "Windows XP" in the forum and found this discussion. [...] Anyone knows if these changes where ever made? Thanks!
Re: Linux shared library loading/linking from C does not invoke (shared) static this
On Tuesday, 12 January 2021 at 09:49:46 UTC, Mike Parker wrote: On Tuesday, 12 January 2021 at 09:31:08 UTC, ichneumwn wrote: Follow on to my own question: on Linux, with gcc, I have created the following file "starter.c" that I inject into my D shared library: int rt_init(void); int rt_term(void); // should really check for errors! static void __attribute__((constructor)) Dstarter(void) { rt_init(); } static void __attribute__((destructor)) Dterminator(void) { rt_term(); } That seems to do the trick. Not sure how clean this is? You should be able to do the same in D with `pragma(crt_constructor)` and `pragma(crt_destructor)`: https://dlang.org/spec/pragma.html#crtctor https://dlang.org/spec/pragma.html#crtdtor https://dlang.org/changelog/2.078.0.html#crt-constructor Perfect, thanks! Interestingly, as I removed the C stub and tried the D route, I noticed that just calling rt_init() is enough to also get static ~this() to run on exit. In fact then adding writeln in a pragma(crt_destructor) function shows that it gets called after static ~this(). For anyone stumbling across this thread and looking for the import for rt_init/term: import core.runtime : rt_init, rt_term;
Re: Linux shared library loading/linking from C does not invoke (shared) static this
On Tuesday, 12 January 2021 at 09:02:38 UTC, Imperatorn wrote: On Tuesday, 12 January 2021 at 08:19:45 UTC, ichneumwn wrote: Where could one file a suggestion for an update to the documentation? In the top right section of the page you can click the "Improve this page"-link. Thanks, I will leave it though. I do not want to mess about and write about something I have just learnt in the last hour. That could do more damage than good.
Re: Linux shared library loading/linking from C does not invoke (shared) static this
On Tuesday, 12 January 2021 at 09:31:08 UTC, ichneumwn wrote: Follow on to my own question: on Linux, with gcc, I have created the following file "starter.c" that I inject into my D shared library: int rt_init(void); int rt_term(void); // should really check for errors! static void __attribute__((constructor)) Dstarter(void) { rt_init(); } static void __attribute__((destructor)) Dterminator(void) { rt_term(); } That seems to do the trick. Not sure how clean this is? You should be able to do the same in D with `pragma(crt_constructor)` and `pragma(crt_destructor)`: https://dlang.org/spec/pragma.html#crtctor https://dlang.org/spec/pragma.html#crtdtor https://dlang.org/changelog/2.078.0.html#crt-constructor
Re: Linux shared library loading/linking from C does not invoke (shared) static this
On Tuesday, 12 January 2021 at 08:19:45 UTC, ichneumwn wrote: Dear all, I was trying to invoke some D code from Python and ran into issues which I eventually traced back to a simple example on the D website itself : https://dlang.org/articles/dll-linux.html Particularly the section "Dynamically Loading a D DLL From a C Program" In my case, and indeed already in 2013 (https://forum.dlang.org/post/yeqyqaaguhngczlnv...@forum.dlang.org), shared static this does not get invoked I normally use: LDC - the LLVM D compiler (1.21.0): based on DMD v2.091.1 and LLVM 10.0.0 (under Linux) but I also tried DMD64 D Compiler v2.095.0 Is the solution suggested in the linked post the "canonical way"? Where could one file a suggestion for an update to the documentation? Cheers! PS Enjoying my project in D especially how easy it is to get the same code to run under windows too Follow on to my own question: on Linux, with gcc, I have created the following file "starter.c" that I inject into my D shared library: int rt_init(void); int rt_term(void); // should really check for errors! static void __attribute__((constructor)) Dstarter(void) { rt_init(); } static void __attribute__((destructor)) Dterminator(void) { rt_term(); } That seems to do the trick. Not sure how clean this is?
Re: Member variables in method are null when called as delegate from thread
On Monday, 11 January 2021 at 17:26:00 UTC, Arafel wrote: void f() { assert(i == 0); // Expected assert(j == 1); // Expected assert(s.i == 0); // Expected assert(s.j == 0); // Wait, what? } At first sight this looks unexpected. But I think if you have a shared variable inside a struct it will not be TLS.
Re: How build DCD on Windows?
On Tuesday, 12 January 2021 at 06:25:09 UTC, evilrat wrote: On Tuesday, 12 January 2021 at 00:35:41 UTC, Marcone wrote: Hi, Someone can Help me build exe dcd server and client on WIndows? Step by step? Becouse the informations disponible is very hard to undestand. Are you serious? It's on the first page of their repo under the Setup section https://code.dlang.org/packages/dcd just clone the repo, open it up in terminal and run the following. it will produce two separate binaries for client and server. Yes, that's all. dub build --build=release --config=client dub build --build=release --config=server I agree, the information may not hard to find, but please be respectful when answering anyway.
Re: Linux shared library loading/linking from C does not invoke (shared) static this
On Tuesday, 12 January 2021 at 08:19:45 UTC, ichneumwn wrote: Where could one file a suggestion for an update to the documentation? In the top right section of the page you can click the "Improve this page"-link.
Linux shared library loading/linking from C does not invoke (shared) static this
Dear all, I was trying to invoke some D code from Python and ran into issues which I eventually traced back to a simple example on the D website itself : https://dlang.org/articles/dll-linux.html Particularly the section "Dynamically Loading a D DLL From a C Program" In my case, and indeed already in 2013 (https://forum.dlang.org/post/yeqyqaaguhngczlnv...@forum.dlang.org), shared static this does not get invoked I normally use: LDC - the LLVM D compiler (1.21.0): based on DMD v2.091.1 and LLVM 10.0.0 (under Linux) but I also tried DMD64 D Compiler v2.095.0 Is the solution suggested in the linked post the "canonical way"? Where could one file a suggestion for an update to the documentation? Cheers! PS Enjoying my project in D especially how easy it is to get the same code to run under windows too