Re: Drawbacks of exceptions being globally allocated
On Monday, 16 August 2021 at 05:36:07 UTC, Tejas wrote: That is why I was using heapAllocate, because using `new` on scope allocates exception on stack, and if you exit, then the exception is basically freed before it even gets caught. It fails even when you catch within the same function. But allocate on heap and giving ownership to a `scope` qualified variable is no problem at all. No `signal 11` killing my process ^_^ You are relying on an accept-invalid though. The compiler *should not* accept that code, but currently erroneously does so.
Re: Drawbacks of exceptions being globally allocated
On Sunday, 15 August 2021 at 20:23:03 UTC, Paul Backus wrote: On Sunday, 15 August 2021 at 18:47:27 UTC, Tejas wrote: Do you see anything wrong with the following `emplace`-allocated, RAII following exceptions: [...] Is this good enough for general use now? Any other drawbacks? It only works if you're throwing and catching in the same function. Otherwise you are essentially returning a pointer to an expired stack frame, which is UB. Guess I should've verified before accepting this as true. ```d import std; import core.lifetime:emplace; import core.stdc.stdlib:malloc; T heapAllocate(T, Args...)(Args args)@nogc{ auto size = __traits(classInstanceSize, T); auto memory = malloc(size)[0 .. size]; auto instance = emplace!(T,Args)(memory, args); return instance; } void throws()@nogc{ scope a = heapAllocate!(Exception)("works fine with scope, apparently"); throw a; } void main()@nogc { try{ throws(); } catch(Exception exp){ printf("%s", cast(char*)exp.msg); } } ``` That is why I was using heapAllocate, because using `new` on scope allocates exception on stack, and if you exit, then the exception is basically freed before it even gets caught. It fails even when you catch within the same function. But allocate on heap and giving ownership to a `scope` qualified variable is no problem at all. No `signal 11` killing my process ^_^
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Sunday, 15 August 2021 at 20:41:51 UTC, james.p.leblanc wrote: Greetings, I have been trying to get a working example of slice assignment operator overloading ... and am befuddled. From the spec (section 20.6.2), the code below appears: struct A { int opIndexAssign(int v); // overloads a[] = v int opIndexAssign(int v, size_t[2] x); // overloads a[i .. j] = v int[2] opSlice(size_t x, size_t y); // overloads i .. j } void test() { A a; int v; a[] = v; // same as a.opIndexAssign(v); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); } I have hacked at this trying to get a simple working example. Could anyone guide me here please? Best Regards, James If you're finding the spec too hard, please try Ali's book. I'm sharing the part on operator overloading below: http://ddili.org/ders/d.en/operator_overloading.html Please ping if you still have problems; I'll then write a full program.
Re: Drawbacks of exceptions being globally allocated
On Monday, 16 August 2021 at 02:26:04 UTC, Tejas wrote: Agh >_< if I remove the `scope`and replace it with `auto`? No longer having anything to do with the stack or RAII, just using malloc + emplace instead of GC? Yeah it might leak memory unless the catch block explicitly frees the exception object, but other than that? Yeah, other than needing to manually free the exception it should be fine. Though at that point, you might just be better off using statically-allocated exceptions.
Re: Drawbacks of exceptions being globally allocated
On Sunday, 15 August 2021 at 20:23:03 UTC, Paul Backus wrote: On Sunday, 15 August 2021 at 18:47:27 UTC, Tejas wrote: Do you see anything wrong with the following `emplace`-allocated, RAII following exceptions: [...] Is this good enough for general use now? Any other drawbacks? It only works if you're throwing and catching in the same function. Otherwise you are essentially returning a pointer to an expired stack frame, which is UB. Agh >_< if I remove the `scope`and replace it with `auto`? No longer having anything to do with the stack or RAII, just using malloc + emplace instead of GC? Yeah it might leak memory unless the catch block explicitly frees the exception object, but other than that?
Re: Anyway to achieve the following
On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote: Hi, This is exactly the behaviour I was trying to obtain. It however comes with a fair amount of overhead, as can be seen in the following llvm ir: [...] What you are asking for are reference variables. C++ has them: the example here illustrates the behavior you want. https://www.geeksforgeeks.org/references-in-c/ D does not have them, as mentioned above: https://forum.dlang.org/post/mailman.2714.1628875187.3446.digitalmars-d-le...@puremagic.com So to get the behavior you want, they have to be simulated, which is what this does: https://forum.dlang.org/post/lcrrnszslpyazoziy...@forum.dlang.org Next version: no `toString` and storage passed in by reference rather than by pointer. ``` struct S { int x = 1234; } void main() { import std.stdio; S s; auto p = //construction of a using &(s.x) auto a = Ref!(int)(*p); //auto a = Ref!(int)(s.x); writeln(a); //displays 1234 s.x += 1; writeln(a); //displays 1235 a += 1; writeln(s.x); //displays 1236 } struct Ref(T) { T* ptr; this(ref T x) { ptr = } @property ref T var() { return *ptr; } alias var this; } ``` I see no way to avoid overhead, as I see no simpler simulation.
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Sunday, 15 August 2021 at 21:28:53 UTC, james.p.leblanc wrote: On Sunday, 15 August 2021 at 21:15:02 UTC, Bastiaan Veelo wrote: On Sunday, 15 August 2021 at 20:41:51 UTC, james.p.leblanc — Bastiaan. Bastiaan, Thanks once again, James On Sunday, 15 August 2021 at 21:28:53 UTC, james.p.leblanc wrote: Okay! Great! Thanks everyone Bastiaan, ag0aep6g, and russhy ... I see more replies come in while I was typing. There is some excellent information here that I need to digest. I believe that I have what I need. This group has been great! BR, James
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Sunday, 15 August 2021 at 21:15:02 UTC, Bastiaan Veelo wrote: On Sunday, 15 August 2021 at 20:41:51 UTC, james.p.leblanc — Bastiaan. Bastiaan, Thanks kindly for your response! Unfortunately, I do not see what the program does. I mean A is a structure that has only functions. So, how are any elements of this being set to the value of v? I tried extending the code mentioned by adding a member array, but no luck. I often have difficulties to understand the notations used in the spec, and only sometimes can I extend them to working examples. Would it be possible to add the last couple of details regarding an array member? I attempted but the values always remain zero even when I set v=4. import std; struct A { int[5] a; int opIndexAssign(int v) // overloads a[] = v { writeln(__FUNCTION__); return 42; } int opIndexAssign(int vh, size_t[2] x) // overloads a[i .. j] = v { writeln(__FUNCTION__); return 43; } int[2] opSlice(size_t x, size_t y) // overloads i .. j { writeln(__FUNCTION__); return [44, 45]; } } void main() { A a; int v=4; writeln(a); a[] = v; // same as a.opIndexAssign(v); writeln(a); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); writeln(a); } Thanks once again, James
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
There is an example here: http://www.rosettacode.org/wiki/Multi-dimensional_array#D Look at the Matrix struct
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Sunday, 15 August 2021 at 20:41:51 UTC, james.p.leblanc wrote: I have been trying to get a working example of slice assignment operator overloading ... and am befuddled. From the spec (section 20.6.2), the code below appears: struct A { int opIndexAssign(int v); // overloads a[] = v int opIndexAssign(int v, size_t[2] x); // overloads a[i .. j] = v int[2] opSlice(size_t x, size_t y); // overloads i .. j } void test() { A a; int v; a[] = v; // same as a.opIndexAssign(v); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); } I have no experience with this, but from a cursory look it seems that that example is wrong. For starters, the type of `opIndexAssign`'s second parameter must match the return type of `opSlice`. This is easily fixed, but the code still doesn't work. Further down on the spec page [1], there is this little table: | op| rewrite | |---|--| | `arr[1, 2..3, 4] = c` | `arr.opIndexAssign(c, 1, arr.opSlice!1(2, 3), 4)`| | `arr[2, 3..4] += c` | `arr.opIndexOpAssign!"+"(c, 2, arr.opSlice!1(2, 3))` | Note the `!1` on `opSlice`. So you need to make `opSlice` a template with an integer parameter. Working example: ```d import std.stdio; struct A { int opIndexAssign(int v, size_t[2] x) { writeln("opIndexAssign: ", v, ", ", x); return v; } size_t[2] opSlice(size_t i)(size_t x, size_t y) { return [x, y]; } } void main() { A a; int v = 42; a[3..4] = v; /* Prints "opIndexAssign: 42, [3, 4]". */ } ``` [1] https://dlang.org/spec/operatoroverloading.html#slice
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Sunday, 15 August 2021 at 20:41:51 UTC, james.p.leblanc wrote: struct A { int opIndexAssign(int v); // overloads a[] = v int opIndexAssign(int v, size_t[2] x); // overloads a[i .. j] = v int[2] opSlice(size_t x, size_t y); // overloads i .. j } void test() { A a; int v; a[] = v; // same as a.opIndexAssign(v); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); } I have hacked at this trying to get a simple working example. Not sure if this does enough of what you’re looking for, but this covers the minimal steps to get it working: https://run.dlang.io/is/m5svQ2 ```d import std; struct A { int opIndexAssign(int v) // overloads a[] = v { writeln(__FUNCTION__); return 42; } int opIndexAssign(int vh, size_t[2] x) // overloads a[i .. j] = v { writeln(__FUNCTION__); return 43; } int[2] opSlice(size_t x, size_t y) // overloads i .. j { writeln(__FUNCTION__); return [44, 45]; } } void main() { A a; int v; a[] = v; // same as a.opIndexAssign(v); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); } ``` — Bastiaan.
Getting a working example of opIndexAssign using opSlice ... have troubles ...
Greetings, I have been trying to get a working example of slice assignment operator overloading ... and am befuddled. From the spec (section 20.6.2), the code below appears: struct A { int opIndexAssign(int v); // overloads a[] = v int opIndexAssign(int v, size_t[2] x); // overloads a[i .. j] = v int[2] opSlice(size_t x, size_t y); // overloads i .. j } void test() { A a; int v; a[] = v; // same as a.opIndexAssign(v); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); } I have hacked at this trying to get a simple working example. Could anyone guide me here please? Best Regards, James
Re: Drawbacks of exceptions being globally allocated
On Sunday, 15 August 2021 at 18:47:27 UTC, Tejas wrote: Do you see anything wrong with the following `emplace`-allocated, RAII following exceptions: [...] Is this good enough for general use now? Any other drawbacks? It only works if you're throwing and catching in the same function. Otherwise you are essentially returning a pointer to an expired stack frame, which is UB.
Re: Drawbacks of exceptions being globally allocated
On Sunday, 15 August 2021 at 16:23:25 UTC, Ali Çehreli wrote: On 8/15/21 2:10 AM, Alexandru Ermicioi wrote: >> This may be useful in some cases but in general, these colatteral >> exceptions don't carry much information and I don't think anybody >> looks at them. Usually, the first one is the one that explains the >> error case. > That is just an assumption. Agreed but it's based on hands-on experience as well as exposure to these forums. :) > There could be designs where original > exception gets wrapped in another one Wrapping is different and yes, it is useful. There have been cases where I hit a ConvException which only tells me a conversion failed. I do catch and augment it in outer contexts to saying something similar ot "That happened while doing this". > Regarding exception chaining, do you mean that it will automatically get > chained, even without explicitly passing it as constructor of wrapping > exception? Yes. That's the functionality which isn't very useful because the collateral exceptions are usually because of the main one: Imagine the file system is full and a destructor cannot flush a file. The destructor's error is not interesting in this case. class Main : Exception { this() { super("Main failed"); } } class Dtor : Exception { this() { super("The destructor failed"); } } struct S { ~this() { throw new Dtor(); } } import std.stdio; void main() { try { auto s = S(); throw new Main(); } catch (Exception exc) { stderr.writeln("Failed: ", exc.msg); stderr.writeln("This failed too: ", exc.next.msg); // (Of course, real code should stop when 'next' is null.) } } That output contains two automatically chained exceptions: Failed: Main failed This failed too: The destructor failed Ali Do you see anything wrong with the following `emplace`-allocated, RAII following exceptions: ```d import std; import core.stdc.stdlib; class Main : Exception { this() @nogc{ super("Main Failed"); } } class Dtor : Exception { this() @nogc{ super("The destructor failed"); } } T heapAllocate(T, Args...)(Args args)@nogc{ auto size = __traits(classInstanceSize, T); auto memory = malloc(size)[0 .. size]; auto instance = emplace!(T,Args)(memory, args); return instance; } struct S { ~this()@nogc { scope a = heapAllocate!Dtor(); throw a; } } void main() @nogc{ try { auto s = S(); scope a = heapAllocate!Main(); throw a; } catch (Exception exc) { printf("Failed: %s\n", cast(char*)exc.msg); printf("This failed too: %s\n", cast(char*)exc.next.msg); // (Of course, real code should stop when 'next' is null.) } } ``` Is this good enough for general use now? Any other drawbacks?
Re: partial initialization of fixed size ("static") arrays
On Saturday, 14 August 2021 at 23:09:14 UTC, Paul Backus wrote: On Saturday, 14 August 2021 at 14:04:47 UTC, kdevel wrote: ~~~ char [7] d7 = "x"; // okay string s = "x"; char [7] c7 = s; // throws RangeError ~~~ What justifies that the compiler behaves differently on two terms ('s', '"x"') which are of equal size, type, length and value? Literals in D can have different types in different contexts. For example: ```d byte b = 16; // 16 is treated as a byte literal int n = 16; // 16 is treated as an int literal b = n; // Error: cannot convert int to byte ``` The wording of the error message ~~~d void main () // bi.d { byte b = 257; } $ dmd bi.d bi.d(3): Error: cannot implicitly convert expression `257` of type `int` to `byte` ~~~ does not seem to support your interpretation. The term `257` does not encode a ‘polymorphic’ entity but the int value 257 which is used to initialize a variable. If necessary, the value is converted. The literal is not “typeless” as in Go [1] either. Similarly, the string literal `"x"` can be treated either as a `string` (a dynamic array of `immutable(char)`) or as a static array of `char`, depending on the type of variable it's assigned to. [1] https://blog.golang.org/constants
Re: Drawbacks of exceptions being globally allocated
On Sunday, 15 August 2021 at 16:23:25 UTC, Ali Çehreli wrote: That output contains two automatically chained exceptions: Failed: Main failed This failed too: The destructor failed Ali Hmm, wasn't aware of such use case (results of too much java :)). Considering this case I'd say it is better to keep it, because having more info than less is better for debugging. Even in your example, you already catch an use case that wasn't accounted for, that may or may not require fixing, i.e. it is better to know it then be in blissfull unawareness. Though it is annoying to view those chained stacks, since they have repetitions. It would be nice if stack traces of nested exceptions would just show lines up to next exception thrown similar to how java does. Regards, Alexandru
Re: Anyway to achieve the following
On Sunday, 15 August 2021 at 16:49:22 UTC, Paul Backus wrote: On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote: Hi, This is exactly the behaviour I was trying to obtain. It however comes with a fair amount of overhead, as can be seen in the following llvm ir: [...] I'm not really familiar with llvm ir, but looking at it on godbolt, it seems like the main difference is that taking the address of `s.x` forces the compiler to place `s` in memory, rather than keeping it entirely in registers: https://d.godbolt.org/z/1afbsM6fv The function `std.stdio.writeln!(example.Ref!(int))` is not trivial. I doubt there is a reasonable optimization/transformation path from a call to `std.stdio.writeln!(example.Ref!(int))` to a call to `std.stdio.writeln!(int).writeln(int)`. Without being able to simplify it to that call, `s` has to be put in memory. It's the opaqueness of `std.stdio.writeln!(example.Ref!(int))` and that it (must) takes the address of `s.x` as parameter. -Johan
Re: Anyway to achieve the following
On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote: Hi, This is exactly the behaviour I was trying to obtain. It however comes with a fair amount of overhead, as can be seen in the following llvm ir: [...] I'm not really familiar with llvm ir, but looking at it on godbolt, it seems like the main difference is that taking the address of `s.x` forces the compiler to place `s` in memory, rather than keeping it entirely in registers: https://d.godbolt.org/z/1afbsM6fv
Re: What exactly are the String literrals in D and how they work?
On 8/15/21 2:10 AM, rempas wrote: So when I'm doing something like the following: `string name = "John";` Then what's the actual type of the literal `"John"`? In the chapter [Calling C functions](https://dlang.org/spec/interfaceToC.html#calling_c_functions) in the "Interfacing with C" page, the following is said: Strings are not 0 terminated in D. See "Data Type Compatibility" for more information about this. However, string literals in D are 0 terminated. Which is really interesting and makes me suppose that `"John"` is a string literal right? However, when I'm writing something like the following: `char *name = "John";`, then D will complain with the following message: Error: cannot implicitly convert expression `"John"` of type `string` to `char*` Which is interesting because this works in C. If I use `const char*` instead, it will work. I suppose that this has to do with the fact that `string` is an alias for `immutable(char[])` but still this has to mean that the actual type of a LITERAL string is of type `string` (aka `immutable(char[])`). Another thing I can do is cast the literal to a `char*` but I'm wondering what's going on under the hood in this case. Is casting executed at compile time or at runtime? So am I going to have an extra runtime cost having to first construct a `string` and then ALSO cast it to a string literal? I hope all that makes sense and the someone can answer, lol Lots of great responses in this thread! I wanted to stress that a string literal is sort of magic. It has extra type information inside the compiler that is not available in the normal type system. Namely that "this is a literal, and so can morph into other things". To give you some examples: ```d string s = "John"; immutable(char)* cs = s; // nope immutable(char)* cs2 = "John"; // OK! wstring ws = s; // nope wstring ws2 = "John"; // OK! ``` What is going on? Because the compiler knows this is a string *literal*, it can modify the type (and possibly the data itself) at will to match what you are assigning it to. In the case of zero-terminated C strings, it allows usage as a pointer instead of a D array. In the case of different width strings (wstring uses 16-bit code-units), it can actually transform the underlying data to what you wanted. Note that even when you do lose that "literal" magic by assigning to a variable, you can still rely on D always putting a terminating zero in the data segment for a string literal. So it's valid to just do: ```d string s = "John"; printf(s.ptr); As long as you *know* the string came from a literal. -Steve
Re: Drawbacks of exceptions being globally allocated
On 8/15/21 2:10 AM, Alexandru Ermicioi wrote: >> This may be useful in some cases but in general, these colatteral >> exceptions don't carry much information and I don't think anybody >> looks at them. Usually, the first one is the one that explains the >> error case. > That is just an assumption. Agreed but it's based on hands-on experience as well as exposure to these forums. :) > There could be designs where original > exception gets wrapped in another one Wrapping is different and yes, it is useful. There have been cases where I hit a ConvException which only tells me a conversion failed. I do catch and augment it in outer contexts to saying something similar ot "That happened while doing this". > Regarding exception chaining, do you mean that it will automatically get > chained, even without explicitly passing it as constructor of wrapping > exception? Yes. That's the functionality which isn't very useful because the collateral exceptions are usually because of the main one: Imagine the file system is full and a destructor cannot flush a file. The destructor's error is not interesting in this case. class Main : Exception { this() { super("Main failed"); } } class Dtor : Exception { this() { super("The destructor failed"); } } struct S { ~this() { throw new Dtor(); } } import std.stdio; void main() { try { auto s = S(); throw new Main(); } catch (Exception exc) { stderr.writeln("Failed: ", exc.msg); stderr.writeln("This failed too: ", exc.next.msg); // (Of course, real code should stop when 'next' is null.) } } That output contains two automatically chained exceptions: Failed: Main failed This failed too: The destructor failed Ali
Re: What exactly are the String literrals in D and how they work?
Lot's of great information and pointers already. I will try from another angle. :) On 8/14/21 11:10 PM, rempas wrote: > So when I'm doing something like the following: `string name = "John";` > Then what's the actual type of the literal `"John"`? As you say and as the code shows, there are two constructs in that line. The right-hand side is a string literal. The left-hand side is a 'string'. >> Strings are not 0 terminated in D. See "Data Type Compatibility" for >> more information about this. However, string literals in D are 0 >> terminated. The string literal is embedded into the compiled program as 5 bytes in this case: 'J', 'o', 'h', 'n', '\0'. That's the right-hand side of your code above. 'string' is an array in D and arrays are stored as the following pair: size_t length;// The number of elements T * ptr; // The pointer to the first element (This is called a "fat pointer".) So, if we assume that the literal 'John' was placed at memory location 0x1000, then the left-hand side of your code will satisfy the following conditions: assert(name.length == 4);// <-- NOT 5 assert(name.ptr == 0x1000); The important part to note is how even though the string literal was stored as 5 bytes but the string's length is 4. As others said, when we add a character to a string, there is no '\0' involved. Only the newly added char will the added. Functions in D do not need the '\0' sentinel to know where the string ends. The end is already known from the 'length' property. Ali
Re: how to import .lib library
On Sunday, 15 August 2021 at 10:12:17 UTC, Timofeyka wrote: Thank you for your reply! I wanted to link to my project another project without source code. This tutorial can help you create yours libs: https://wiki.dlang.org/Win32_DLLs_in_D
Re: how to import .lib library
On Sunday, 15 August 2021 at 09:49:39 UTC, Timofeyka wrote: Hello! I may have a very stupid question, but still. How do I include a .lib library? How to use it in your code? Inside the source code you can use pragma. Example: pragma(lib, "gdi32.lib"); In DMD command line you can use -L flag that pass the lib to linker. Example: dmd -Lgdi32.lib mycode.d
Re: how to import .lib library
On Sunday, 15 August 2021 at 10:40:36 UTC, jfondren wrote: Yeah, that's not possible. You either need the source or a set of D interface files that declares all the symbols you need. Meaning, it is possible. On Windows where I assume these .lib files are: I mentioned C libraries in an earlier post. But the OP did not say whether the library is a C library or a D one. If it's a D library, then you can't simply declare the functions locally because the module name is part of the fully-qualifed name. You absolutely need the source or the interface files. Declaring C functions locally where you need them is fine if you only need a handful of sybmols. But when you need multiple functions and types from the API, that's going to get unwieldy.
Re: how to import .lib library
On Sunday, 15 August 2021 at 10:19:33 UTC, Mike Parker wrote: On Sunday, 15 August 2021 at 10:12:17 UTC, Timofeyka wrote: Thank you for your reply! I wanted to link to my project another project without source code. Yeah, that's not possible. You either need the source or a set of D interface files that declares all the symbols you need. Meaning, it is possible. On Windows where I assume these .lib files are: ``` PS C:\Users\jfond> cat math.d extern(C) int twice(int n) { return n * 2; } PS C:\Users\jfond> cat mathuser.d extern (C) int twice(int n); void main() { import std.stdio : writeln; writeln(twice(21)); } PS C:\Users\jfond> ldc2 -lib math.d PS C:\Users\jfond> ldc2 mathuser.d math.lib PS C:\Users\jfond> ./mathuser 42 ``` math.lib is written in D but it could've been written just as well in C or C++ or anything, as long as it's targeting the C ABI in whatever language. When mathuser.d is compiled, D does not need the source for math.lib. That one extern(C) function without a body is sufficient to, again targeting the C ABI, say "I am expecting to be linked with a function like this", and math.lib supplies that function at link time. D is identical to pretty much every other native-compiled language in this respect. The question you probably want to be asking is, "given a specific library from this vendor, what's the most *convenient* way to link D against it", or "how should I tell dub to link this D application with a .lib file in a parent directory", etc.
Re: Nondeterministic unittest debugging problem.
Note you might need to open the screenshots externally, as they are cut off by the forum.
Nondeterministic unittest debugging problem.
I am unsure where to mention this as I am utterly lost as to what the issue is, which I can simply best describe with 2 screenshots. Though I'll first give a short description. For some reason my debugger is "\" for one of my variables in one of my unittests. This is however not the case when a random unused variable is inserted in front of it. (For reference I'm building the unittest using something similar to `dub build --build=unittest --config=unittest --force --archType=x86_64`, though the project is a library thus there are some complications: https://github.com/dlang/dub/issues/1856#issuecomment-899022431) Not readable: ![](https://www.dropbox.com/s/j6bt3gaxu05om2j/Fout.png?dl=0=1) Readable: ![](https://www.dropbox.com/s/lnj3ugmuoh339oi/Fout2.png?dl=0=1) ```d int x = 0; Mat!(3, 3, float) a = Mat!(3, 3, float)([1, 2, 3, 4, 5, 6, 7, 8, 9]); ``` Note the x variable is entirely unused while Mat is a struct of a union that is essentially just a 2d array of floats. I have no more clue where to look as I have no clue what could cause this, am I overlooking something trivial? Thanks in advance.
Re: how to import .lib library
On Sunday, 15 August 2021 at 10:12:17 UTC, Timofeyka wrote: Thank you for your reply! I wanted to link to my project another project without source code. Yeah, that's not possible. You either need the source or a set of D interface files that declares all the symbols you need. The compiler *has* to be able to see the symbols to know what's available for you to use.
Re: how to import .lib library
On Sunday, 15 August 2021 at 10:05:15 UTC, Mike Parker wrote: You don't import a .lib file. They are for the linker, not the compiler. How you make use of it depends on what sort of library it is and how you're building your project. If this is all new to you, it will be easier just to specify here which library it is that you're wanting to use, then I or someone else can give you directions. But the general idea is as follows. If it's a D library, you'll need access to the source code (or alternatively, D interface files that have a .di extension, but that's another topic). That's what you use at compile time via the `import` statement. When you import, for example, `std.stdio`, you are importing the module from the Phobos source tree that ships with the compiler. If the library is registered with the dub repository, then you can use dub to manage and build your project to make life easier. The library's source will be available to import, and dub will build the library and make sure it's linked. If the library is not registered with dub, you'll need to download the source somewhere, make sure it's on the import path (use the `-I` switch on the compiler command line with the source path, e.g., `-I/path/to/source`), you'll need to make sure the library is compiled separately from your project, and then you'll need to give the lib file to the compiler on the command line along with your source (e.g., `dmd app.d library.lib`). If it's a C library, you'll need to translate the C API to D (not the source code, just the type and function declarations) if it hasn't been done already. Then you import the translated D files and give the .lib file to the compiler as above. Thank you for your reply! I wanted to link to my project another project without source code.
Re: how to import .lib library
On Sunday, 15 August 2021 at 09:49:39 UTC, Timofeyka wrote: Hello! I may have a very stupid question, but still. How do I include a .lib library? How to use it in your code? You don't import a .lib file. They are for the linker, not the compiler. How you make use of it depends on what sort of library it is and how you're building your project. If this is all new to you, it will be easier just to specify here which library it is that you're wanting to use, then I or someone else can give you directions. But the general idea is as follows. If it's a D library, you'll need access to the source code (or alternatively, D interface files that have a .di extension, but that's another topic). That's what you use at compile time via the `import` statement. When you import, for example, `std.stdio`, you are importing the module from the Phobos source tree that ships with the compiler. If the library is registered with the dub repository, then you can use dub to manage and build your project to make life easier. The library's source will be available to import, and dub will build the library and make sure it's linked. If the library is not registered with dub, you'll need to download the source somewhere, make sure it's on the import path (use the `-I` switch on the compiler command line with the source path, e.g., `-I/path/to/source`), you'll need to make sure the library is compiled separately from your project, and then you'll need to give the lib file to the compiler on the command line along with your source (e.g., `dmd app.d library.lib`). If it's a C library, you'll need to translate the C API to D (not the source code, just the type and function declarations) if it hasn't been done already. Then you import the translated D files and give the .lib file to the compiler as above.
how to import .lib library
Hello! I may have a very stupid question, but still. How do I include a .lib library? How to use it in your code?
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 09:06:14 UTC, Mike Parker wrote: The D `string` is an alias for `immutable(char)[]`, immutable contents of a mutable array reference (`immutable(char[])` would mean the array reference is also immutable). You don't want to assign that to a `char*`, because then you'd be able to mutate the contents of the string, thereby violating the contract of immutable. (`immutable` means the data to which it's applied, in this case the contents of an array, will not be mutated through any reference anywhere in the program.) [...] Thanks a lot for the info!
Re: Drawbacks of exceptions being globally allocated
On Sunday, 15 August 2021 at 00:15:32 UTC, Ali Çehreli wrote: Even though this feature is probably never used, in D, multiple exception objects are chained. For example, you can throw e.g. in a destructor when there is an active exception in flight and that second object gets attached to the first one in linked list fashion. This may be useful in some cases but in general, these colatteral exceptions don't carry much information and I don't think anybody looks at them. Usually, the first one is the one that explains the error case. That is just an assumption. There could be designs where original exception gets wrapped in another one to comply with some interface, and in such cases, having entire chain visible, is useful. Also exceptions carry the stack trace which is useful, in debugging, allowing you to know possible location of the bug. Regarding exception chaining, do you mean that it will automatically get chained, even without explicitly passing it as constructor of wrapping exception? If so, it indeed might be best to remove such functionality, and just force user to do this by himself. He will then be able to decide whether chained exception does or does not carry any useful meaning. Regards, Alexandru
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 08:11:39 UTC, rempas wrote: I mean that in C, we can assign a string literal into a `char*` and also a `const char*` type without getting a compilation error while in D, we can only assign it to a `const char*` type. I suppose that's because of C doing explicit conversion. I didn't talked about mutating a string literal The D `string` is an alias for `immutable(char)[]`, immutable contents of a mutable array reference (`immutable(char[])` would mean the array reference is also immutable). You don't want to assign that to a `char*`, because then you'd be able to mutate the contents of the string, thereby violating the contract of immutable. (`immutable` means the data to which it's applied, in this case the contents of an array, will not be mutated through any reference anywhere in the program.) Assigning it to `const(char)*` is fine, because `const` means the data can't be mutated through that particular reference (pointer in this case). And because strings in C are quite frequently represented as `const(char)*`, especially in function parameter lists, D string literals are explicitly convertible to `const(char)*` and also NUL-terminated. So you can do something like `puts("Something")` without worry. This blog post may be helpful: https://dlang.org/blog/2021/05/24/interfacing-d-with-c-strings-part-one/
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 09:01:17 UTC, jfondren wrote: They don't do the same thing. toStringz always copies, always GC-allocates, and always NUL-terminates. `cast(char*)` only does what you want in the case that you're applying it a string literal. But in that case you shouldn't cast, you should just ```d const char* s = "John"; ``` If you need cast cast the const away to work with a C API, doing that separately, at the point of the call to the C function, makes it clearer what you're doing and what the risks are there (does the C function modify the string? If so this will segfault). Yeah I won't cast when having a `const char*`. I already mentioned that it works without cast with `const` variables ;)
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 08:56:07 UTC, rempas wrote: On Sunday, 15 August 2021 at 08:53:50 UTC, Tejas wrote: External C libraries expect strings to be null terminated, so if you do use `.dup`, use `.toStringz` as well. Yeah, yeah I got that. My question is, if I should avoid `cast(char*)` and use `.toStringz` while both do the exact same thing? They don't do the same thing. toStringz always copies, always GC-allocates, and always NUL-terminates. `cast(char*)` only does what you want in the case that you're applying it a string literal. But in that case you shouldn't cast, you should just ```d const char* s = "John"; ``` If you need cast cast the const away to work with a C API, doing that separately, at the point of the call to the C function, makes it clearer what you're doing and what the risks are there (does the C function modify the string? If so this will segfault).
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 08:53:50 UTC, Tejas wrote: External C libraries expect strings to be null terminated, so if you do use `.dup`, use `.toStringz` as well. Yeah, yeah I got that. My question is, if I should avoid `cast(char*)` and use `.toStringz` while both do the exact same thing?
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 08:51:19 UTC, rempas wrote: On Sunday, 15 August 2021 at 08:47:39 UTC, jfondren wrote: dup() isn't aware of the NUL since that's outside the slice of the string. It only copies the chars in "John". You can use toStringz to ensure NUL termination: https://dlang.org/phobos/std_string.html#.toStringz Is there something bad than just casting it to `char*` that I should be aware of? External C libraries expect strings to be null terminated, so if you do use `.dup`, use `.toStringz` as well.
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 08:47:39 UTC, jfondren wrote: dup() isn't aware of the NUL since that's outside the slice of the string. It only copies the chars in "John". You can use toStringz to ensure NUL termination: https://dlang.org/phobos/std_string.html#.toStringz Is there something bad than just casting it to `char*` that I should be aware of?
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 08:11:39 UTC, rempas wrote: On Sunday, 15 August 2021 at 07:43:59 UTC, jfondren wrote: ```d unittest { char* s = "John".dup.ptr; s[0] = 'X'; // no segfaults assert(s[0..4] == "Xohn"); // ok } ``` Well, that one didn't worked out really well for me. Using `.dup.ptr`, didn't added a null terminated character dup() isn't aware of the NUL since that's outside the slice of the string. It only copies the chars in "John". You can use toStringz to ensure NUL termination: https://dlang.org/phobos/std_string.html#.toStringz
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 07:47:27 UTC, jfondren wrote: On Sunday, 15 August 2021 at 07:43:59 UTC, jfondren wrote: On Sunday, 15 August 2021 at 06:10:53 UTC, rempas wrote: ```d unittest { char* s = "John".dup.ptr; s[0] = 'X'; // no segfaults assert(s[0..4] == "Xohn"); // ok } ``` So am I going to have an extra runtime cost having to first construct a `string` and then ALSO cast it to a string literal? In the above case, "John" is a string that's compiled into the resulting executable and loaded into read-only memory, and this code is reached that string is duplicated, at runtime, to create a copy in writable memory. Probably a more useful way to think about this is to consider what happens in a loop: ```d void static_lifetime() @nogc { foreach (i; 0 .. 100) { string s = "John"; // some code } } ``` ^^ At runtime a slice is created on the stack 100 times, with a pointer to the 'J' of the literal, a length of 4, etc. The cost of this doesn't change with the length of the literal, and the bytes of the literal aren't copied, so this code would be just as fast if the string were megabytes in length. ```d void dynamically_allocated() { // no @nogc foreach (i; 0 .. 100) { char[] s = "John".dup; // some code } } ``` ^^ Here, the literal is copied into freshly GC-allocated memory a hundred times, and a slice is made from that. And for completeness: ```d void stack_allocated() @nogc { foreach (i; 0 .. 100) { char[4] raw = "John"; char[] s = raw[0..$]; // some code } } ``` ^^ Here, a static array is constructed on the stack a hundred times, and the literal is copied into the array, and then a slice is constructed on the stack with a pointer into the array on the stack, a length of 4, etc. This doesn't use the GC but the stack is limited in size and now you have worry about the slice getting copied elsewhere and outliving the data on the stack: ```d char[] stack_allocated() @nogc { char[] ret; foreach (i; 0 .. 100) { char[4] raw = "John"; char[] s = raw[0 .. $]; ret = s; } return ret; // errors with -preview=dip1000 } void main() { import std.stdio : writeln; char[] s = stack_allocated(); writeln(s); // prints garbage } ```
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 08:17:47 UTC, rikki cattermole wrote: pragma is a set of commands to the compiler that may be compiler specific. In the case of the msg command, it tells the compiler to output a message to stdout during compilation. Thanks man!
Re: What exactly are the String literrals in D and how they work?
On 15/08/2021 8:11 PM, rempas wrote: Still don't know what "pragma" does but thank you. pragma is a set of commands to the compiler that may be compiler specific. In the case of the msg command, it tells the compiler to output a message to stdout during compilation.
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 07:43:59 UTC, jfondren wrote: ```d unittest { pragma(msg, typeof("John")); // string pragma(msg, is(typeof("John") == immutable(char)[])); // true } ``` Still don't know what "pragma" does but thank you. ```d void zerort(string s) { assert(s.ptr[s.length] == '\0'); } unittest { zerort("John"); // assertion success string s = "Jo"; s ~= "hn"; zerort(s); // assertion failure } ``` If a function takes a string as a runtime parameter, it might not be NUL terminated. This might be more obvious with substrings: ```d unittest { string j = "John"; string s = j[0..2]; assert(s == "Jo"); assert(s.ptr == j.ptr); assert(s.ptr[s.length] == 'h'); // it's h-terminated } ``` That's interesting! ```c void mutate(char *s) { s[0] = 'X'; } int main() { char *s = "John"; mutate(s); // segmentation fault } ``` `char*` is just the wrong type, it suggests mutability where mutability ain't. I mean that in C, we can assign a string literal into a `char*` and also a `const char*` type without getting a compilation error while in D, we can only assign it to a `const char*` type. I suppose that's because of C doing explicit conversion. I didn't talked about mutating a string literal Compile-time. std.conv.to is what you'd use at runtime. Here though, what you want is `dup` to get a `char[]`, which you can then take the pointer of if you want: ```d unittest { char* s = "John".dup.ptr; s[0] = 'X'; // no segfaults assert(s[0..4] == "Xohn"); // ok } ``` Well, that one didn't worked out really well for me. Using `.dup.ptr`, didn't added a null terminated character while `cast(char*)` did. So I suppose the first way is more better when you want a C-like `char*` and not a D-like `char[]`.
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 07:43:59 UTC, jfondren wrote: On Sunday, 15 August 2021 at 06:10:53 UTC, rempas wrote: ```d unittest { char* s = "John".dup.ptr; s[0] = 'X'; // no segfaults assert(s[0..4] == "Xohn"); // ok } ``` So am I going to have an extra runtime cost having to first construct a `string` and then ALSO cast it to a string literal? In the above case, "John" is a string that's compiled into the resulting executable and loaded into read-only memory, and this code is reached that string is duplicated, at runtime, to create a copy in writable memory.
Re: What exactly are the String literrals in D and how they work?
On Sunday, 15 August 2021 at 06:10:53 UTC, rempas wrote: So when I'm doing something like the following: `string name = "John";` Then what's the actual type of the literal `"John"`? ```d unittest { pragma(msg, typeof("John")); // string pragma(msg, is(typeof("John") == immutable(char)[])); // true } ``` In the chapter [Calling C functions](https://dlang.org/spec/interfaceToC.html#calling_c_functions) in the "Interfacing with C" page, the following is said: Strings are not 0 terminated in D. See "Data Type Compatibility" for more information about this. However, string literals in D are 0 terminated. ```d void zerort(string s) { assert(s.ptr[s.length] == '\0'); } unittest { zerort("John"); // assertion success string s = "Jo"; s ~= "hn"; zerort(s); // assertion failure } ``` If a function takes a string as a runtime parameter, it might not be NUL terminated. This might be more obvious with substrings: ```d unittest { string j = "John"; string s = j[0..2]; assert(s == "Jo"); assert(s.ptr == j.ptr); assert(s.ptr[s.length] == 'h'); // it's h-terminated } ``` Which is really interesting and makes me suppose that `"John"` is a string literal right? However, when I'm writing something like the following: `char *name = "John";`, then D will complain with the following message: Error: cannot implicitly convert expression `"John"` of type `string` to `char*` Which is interesting because this works in C. Well, kinda: ```c void mutate(char *s) { s[0] = 'X'; } int main() { char *s = "John"; mutate(s); // segmentation fault } ``` `char*` is just the wrong type, it suggests mutability where mutability ain't. If I use `const char*` instead, it will work. I suppose that this has to do with the fact that `string` is an alias for `immutable(char[])` but still this has to mean that the actual type of a LITERAL string is of type `string` (aka `immutable(char[])`). Another thing I can do is cast the literal to a `char*` but I'm wondering what's going on under the hood in this case. The same thing as in C: ```d void mutate(char *s) { s[0] = 'X'; } void main() { char* s = cast(char*) "John"; mutate(s); // program killed by signal 11 } ``` Is casting executed at compile time or at runtime? Compile-time. std.conv.to is what you'd use at runtime. Here though, what you want is `dup` to get a `char[]`, which you can then take the pointer of if you want: ```d unittest { char* s = "John".dup.ptr; s[0] = 'X'; // no segfaults assert(s[0..4] == "Xohn"); // ok } ``` So am I going to have an extra runtime cost having to first construct a `string` and then ALSO cast it to a string literal? I hope all that makes sense and the someone can answer, lol
Re: Anyway to achieve the following
On Saturday, 14 August 2021 at 20:50:47 UTC, Carl Sturtivant wrote: ``` struct S { int x = 1234; } void main() { import std.stdio; S s; //construction of a using &(s.x) auto a = Ref!(int)(); writeln(a); //displays 1234 s.x += 1; writeln(a); //displays 1235 a += 1; writeln(s.x); //displays 1236 } struct Ref(T) { T* ptr; this(T* p) { ptr = p; } string toString() { import std.conv; return to!string(*ptr); } ref T var() { return *ptr; } alias var this; } ``` Hi, This is exactly the behaviour I was trying to obtain. It however comes with a fair amount of overhead, as can be seen in the following llvm ir: define i32 @_Dmain({ i64, { i64, i8* }* } %unnamed) #0 { %s = alloca %onlineapp.S, align 4 ; [#uses = 4, size/byte = 4] %a = alloca %"onlineapp.Ref!int.Ref", align 8 ; [#uses = 5, size/byte = 8] %1 = bitcast %onlineapp.S* %s to i8*; [#uses = 1] call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %1, i8* align 1 bitcast (%onlineapp.S* @onlineapp.S.__init to i8*), i64 4, i1 false) %2 = bitcast %"onlineapp.Ref!int.Ref"* %a to i8* ; [#uses = 1] call void @llvm.memset.p0i8.i64(i8* align 1 %2, i8 0, i64 8, i1 false) %3 = getelementptr inbounds %onlineapp.S, %onlineapp.S* %s, i32 0, i32 0 ; [#uses = 1, type = i32*] %4 = call %"onlineapp.Ref!int.Ref"* @pure nothrow ref @nogc @safe onlineapp.Ref!(int).Ref onlineapp.Ref!(int).Ref.__ctor(int*)(%"onlineapp.Ref!int.Ref"* nonnull returned %a, i32* %3) #4 ; [#uses = 0] %5 = load %"onlineapp.Ref!int.Ref", %"onlineapp.Ref!int.Ref"* %a, align 8 ; [#uses = 1] call void @@safe void std.stdio.writeln!(onlineapp.Ref!(int).Ref).writeln(onlineapp.Ref!(int).Ref)(%"onlineapp.Ref!int.Ref" %5) #4 %6 = getelementptr inbounds %onlineapp.S, %onlineapp.S* %s, i32 0, i32 0 ; [#uses = 2, type = i32*] %7 = load i32, i32* %6, align 4 ; [#uses = 1] %8 = add i32 %7, 1 ; [#uses = 1] store i32 %8, i32* %6, align 4 %9 = load %"onlineapp.Ref!int.Ref", %"onlineapp.Ref!int.Ref"* %a, align 8 ; [#uses = 1] call void @@safe void std.stdio.writeln!(onlineapp.Ref!(int).Ref).writeln(onlineapp.Ref!(int).Ref)(%"onlineapp.Ref!int.Ref" %9) #4 %10 = call i32* @pure nothrow ref @nogc @safe int onlineapp.Ref!(int).Ref.var()(%"onlineapp.Ref!int.Ref"* nonnull %a) #4 ; [#uses = 2] %11 = load i32, i32* %10, align 4 ; [#uses = 1] %12 = add i32 %11, 1; [#uses = 1] store i32 %12, i32* %10, align 4 %13 = getelementptr inbounds %onlineapp.S, %onlineapp.S* %s, i32 0, i32 0 ; [#uses = 1, type = i32*] %14 = load i32, i32* %13, align 4 ; [#uses = 1] call void @@safe void std.stdio.writeln!(int).writeln(int)(i32 %14) #4 ret i32 0 }
What exactly are the String literrals in D and how they work?
So when I'm doing something like the following: `string name = "John";` Then what's the actual type of the literal `"John"`? In the chapter [Calling C functions](https://dlang.org/spec/interfaceToC.html#calling_c_functions) in the "Interfacing with C" page, the following is said: Strings are not 0 terminated in D. See "Data Type Compatibility" for more information about this. However, string literals in D are 0 terminated. Which is really interesting and makes me suppose that `"John"` is a string literal right? However, when I'm writing something like the following: `char *name = "John";`, then D will complain with the following message: Error: cannot implicitly convert expression `"John"` of type `string` to `char*` Which is interesting because this works in C. If I use `const char*` instead, it will work. I suppose that this has to do with the fact that `string` is an alias for `immutable(char[])` but still this has to mean that the actual type of a LITERAL string is of type `string` (aka `immutable(char[])`). Another thing I can do is cast the literal to a `char*` but I'm wondering what's going on under the hood in this case. Is casting executed at compile time or at runtime? So am I going to have an extra runtime cost having to first construct a `string` and then ALSO cast it to a string literal? I hope all that makes sense and the someone can answer, lol