Re: Removing elements from dynamic arrays?
On Wednesday, 6 April 2022 at 19:28:53 UTC, Steven Schveighoffer wrote: With `arr.find!(someLambda)`, if the lambda is using data from outside the lambda, it needs a closure, which means it may (probably does) allocate your needed data into a GC heap block that will then become garbage after the function is gone. With `arr.find(value)`, it searches the array for something that compares with the value. No allocation happens, and it's equivalent to what you would write in a for loop. Especially for the code in question: ```d arr.find(val); // like a for loop, comparing each element to val arr.find!(v => v == val); // requires a context pointer for val, may allocate. ``` There is no difference functionally -- both perform exactly the same task, but one is just more expensive. There shouldn't be any significant difference in performance. A good optimizing compiler is expected to ensure that templates/lambdas are inlined here and no heap/GC allocation happens. Unfortunately DMD is not an optimizing compiler and this indeed may have some impact on the preferred coding style if people really care about the performance of their code even when it is compiled by DMD. Lambdas and closures aren't even a unique feature of D language. C++ supports them too and sets the bar for performance expectations: https://www.elbeno.com/blog/?p=1068 Currently my own preferred performance test for the optimizing D compiler quality would be this solution of https://atcoder.jp/contests/abc230/tasks/abc230_e based on binary search: * https://atcoder.jp/contests/abc230/submissions/27673369 (D) * https://atcoder.jp/contests/abc230/submissions/27743857 (C++) * https://atcoder.jp/contests/abc230/submissions/27741770 (D with gallopBackwards search policy as a bonus) Using templates from Phobos as building blocks, chaining them together via UFCS and using a lambda is expected to be roughly as efficient as implementing an imperative binary search loop. If this isn't the case, then there's a defect in the compiler to be investigated and fixed.
Re: Removing elements from dynamic arrays?
On 4/6/22 2:32 PM, Salih Dincer wrote: On Wednesday, 6 April 2022 at 16:54:26 UTC, Steven Schveighoffer wrote: This is almost equivalent, but it requires a lambda and an allocation. So I'm not sure what thing you are trying to do here. **Source Code:** https://forum.dlang.org/post/pxkhngxmqgiwwymmg...@forum.dlang.org Actually, I wrote this before, with a few magic touches, I got what I wanted. I'm not sure what your code there is trying to do exactly. What I meant with my comment above is this: With `arr.find!(someLambda)`, if the lambda is using data from outside the lambda, it needs a closure, which means it may (probably does) allocate your needed data into a GC heap block that will then become garbage after the function is gone. With `arr.find(value)`, it searches the array for something that compares with the value. No allocation happens, and it's equivalent to what you would write in a for loop. Especially for the code in question: ```d arr.find(val); // like a for loop, comparing each element to val arr.find!(v => v == val); // requires a context pointer for val, may allocate. ``` There is no difference functionally -- both perform exactly the same task, but one is just more expensive. -Steve
Re: Looking for a workaround
On Wednesday, 6 April 2022 at 18:21:11 UTC, Adam D Ruppe wrote: On Wednesday, 6 April 2022 at 18:10:32 UTC, Guillaume Piolat wrote: Any idea how to workaround that? Works fine if you just use the language instead of the buggy phobos wrappers: --- struct MyUDA { } class A { @MyUDA int a; } class B : A { @MyUDA int b; } void main() { foreach(memberName; __traits(allMembers, B)) foreach(attr; __traits(getAttributes, __traits(getMember, B, memberName))) static if(is(attr == MyUDA)) pragma(msg, memberName); // a, b } --- So make a function that does that and applies whatever it is you need to apply and you're in business. Note that it is `is(typeof(attr) == MyUDA)` if defined `@MyUDA(args)`. Thanks, it will also create less templates.
Re: Removing elements from dynamic arrays?
On Wednesday, 6 April 2022 at 16:54:26 UTC, Steven Schveighoffer wrote: This is almost equivalent, but it requires a lambda and an allocation. So I'm not sure what thing you are trying to do here. I tried to get these results but it didn't work: abc efg h [0, 3] [4, 7] [8, 9] abcefgh I'm a bit old-fashioned and I don't understand these lambda stuff. That's why I coded with classical logic and indexOf... **Source Code:** https://forum.dlang.org/post/pxkhngxmqgiwwymmg...@forum.dlang.org Actually, I wrote this before, with a few magic touches, I got what I wanted. SDB@79
Re: Looking for a workaround
On Wednesday, 6 April 2022 at 18:10:32 UTC, Guillaume Piolat wrote: Any idea how to workaround that? Works fine if you just use the language instead of the buggy phobos wrappers: --- struct MyUDA { } class A { @MyUDA int a; } class B : A { @MyUDA int b; } void main() { foreach(memberName; __traits(allMembers, B)) foreach(attr; __traits(getAttributes, __traits(getMember, B, memberName))) static if(is(attr == MyUDA)) pragma(msg, memberName); // a, b } --- So make a function that does that and applies whatever it is you need to apply and you're in business. Note that it is `is(typeof(attr) == MyUDA)` if defined `@MyUDA(args)`.
Looking for a workaround
This program fails to build: import std.traits: getSymbolsByUDA; struct MyUDA { } class A { @MyUDA int a; } class B : A { @MyUDA int b; } void main() { alias G = getSymbolsByUDA!(B, MyUDA); } Output: c:\d\ldc2-1.28.0-windows-multilib\bin\..\import\std\traits.d(8933): Error: template instance `AliasSeq!(b, a)` `AliasSeq!(b, a)` is nested in both `B` and `A` c:\d\ldc2-1.28.0-windows-multilib\bin\..\import\std\traits.d(8707): Error: template instance `std.traits.getSymbolsByUDAImpl!(B, MyUDA, "b", "a", "toString", "toHash", "opCmp", "opEquals", "Monitor", "factory")` error instantiating main.d(19):instantiated from here: `getSymbolsByUDA!(B, MyUDA)` Failed: ["c:\\d\\ldc2-1.28.0-windows-multilib\\bin\\ldmd2.exe", "-v", "-o-", "main.d", "-I."] Any idea how to workaround that? I really need the same UDA in parent and child class.
Re: Mixin Templates and Operators
On Wednesday, 6 April 2022 at 17:33:28 UTC, Steven Schveighoffer wrote: As I mentioned elsewhere, it does work. But the situation I think must be that it's only one mixin template. Probably also you can't have any overloads in the type itself. ooh yeah there's multiple here so the names don't overload and one on the time itself would override the ones from mixin template. You'd have to alias them together on the type.
Re: Mixin Templates and Operators
On 4/6/22 12:52 PM, Adam D Ruppe wrote: On Wednesday, 6 April 2022 at 10:36:04 UTC, francesco.andreetto wrote: Am I doing something wrong or it is impossible to use mixin templates like that? mixin templates can't bring in operator overloads. The spec doesn't really say this I think, but that's the way it has been for a long time. It only checks for operator overloads on the direct thing itself, no UFCS, no mixin template. As I mentioned elsewhere, it does work. But the situation I think must be that it's only one mixin template. Probably also you can't have any overloads in the type itself. Note that I also think string mixins would work perfectly fine. And UFCS will never work for operator overloads, but that is by design. -Steve
Re: Mixin Templates and Operators
On 4/6/22 6:36 AM, francesco.andreetto wrote: I have two structs, point and vec, in which I want to implement some arithmetic operations. The operations are: ``` point - point = vec point + vec = point ``` Using mixin templates the code compiles but calling the operations in the main causes an "incompatible type" Error: This seems like a bug in the compiler. You can mixin operator overloads using one mixin template, but not multiple. e.g. raylib-d uses this: https://github.com/schveiguy/raylib-d/blob/89733bab9fd1d3588c14f4aa54b62ad45022a105/source/raymathext.d#L75 I tried to implement a single template: ```d mixin template sumDiff(T, R){ R opBinary(string op)(T rhs) const if (op == "+" || op == "-"){ return mixin("R(x " ~ op ~ " rhs.x, y " ~ op ~ "rhs.y, z " ~ op ~ " rhs.z)"); } } ``` but the same error occurs. This is different from your original. If I do this, it works: ```d mixin template both(T, R) { R opBinary(string op : "+")(T rhs) const { return R(x + rhs.x, y + rhs.y, z + rhs.z); } T opBinary(string op : "-")(R rhs) const { return T(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin both!(vec, point); } ``` If I don't use the mixin templates and, instead, I overload the operations into the structures everything works. It also works to call `opBinary` directly: ```d vec v1 = p1.opBinary!"-"(p2); ``` Which leads me to believe it's not an ambiguity error, but rather just a straight omission on how the operator overloading works. I think you should file a bug. -Steve
Re: Removing elements from dynamic arrays?
On 4/5/22 11:47 PM, Salih Dincer wrote: On Tuesday, 5 April 2022 at 14:10:44 UTC, Steven Schveighoffer wrote: [...] I'd implement it probably like this (for D2): ```d auto drop(T)(ref T[] arr, T which) { import std.algorithm, std.range; auto f = arr.find(which); debug if(f.empty) throw ...; auto result = arr.front; arr = arr.remove(&f[0] - &arr[0]); // god I hate this return result; } ``` First, you're neglecting the loop. oops, yes, that should have been `auto result = f.front` Second, the returned value is the first element of the array. It should be as follows: ```d auto drop2(T)(ref T[] arr, T which) { //auto f = arr.find(which); auto f = arr.find!(a => a == which); This is almost equivalent, but it requires a lambda and an allocation. So I'm not sure what thing you are trying to do here. //debug if(f.empty) throw ...; auto result = f.front; // arr.front; Yep, that's a bug on my part. //arr = arr.remove(&f[0] - &arr[0]); arr = remove!(a => a == which)(arr); This runs through the array again, instead of just removing the one index that you already know. And also, the original code only removed one element, even if there were multiple matches. Yours removes them all. return result; } ``` We do not know the wishes of the programmer who made the development. But it is certain that he scanned until the end of the array. So it doesn't make sense for the resulting output to be equal to the ```which```. In summary, one line is enough: ```d return remove!(a => a == which)(arr); ``` The return is the element that was removed, not the array after removing the element. And even though it might feel equivalent to return the input, we don't know how the elements compare, so the array element might be different than the incoming parameter. -Steve
Re: Mixin Templates and Operators
On Wednesday, 6 April 2022 at 10:36:04 UTC, francesco.andreetto wrote: Am I doing something wrong or it is impossible to use mixin templates like that? mixin templates can't bring in operator overloads. The spec doesn't really say this I think, but that's the way it has been for a long time. It only checks for operator overloads on the direct thing itself, no UFCS, no mixin template.
Re: Mixin Templates and Operators
On Wednesday, 6 April 2022 at 10:36:04 UTC, francesco.andreetto wrote: I have two structs, point and vec, in which I want to implement some arithmetic operations. The operations are: ``` point - point = vec point + vec = point ``` Using mixin templates the code compiles but calling the operations in the main causes an "incompatible type" Error: ```d mixin template sum(T, R) { R opBinary(string op)(T rhs) const if (op == "+"){ return R(x + rhs.x, y + rhs.y, z + rhs.z); } } mixin template diff(T, R) { R opBinary(string op)(T rhs) const if (op == "-") { return R(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin diff!(point, vec); mixin sum!(vec, point); } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` The output of `dub run` is ``` Performing "debug" build using /usr/bin/dmd for x86_64. query ~master: building configuration "application"... source/app.d(27,13): Error: incompatible types for `(p1) - (p2)`: both operands are of type `point` source/app.d(30,15): Error: incompatible types for `(p1) + (v2)`: `point` and `vec` /usr/bin/dmd failed with exit code 1. ``` I tried to implement a single template: ```d mixin template sumDiff(T, R){ R opBinary(string op)(T rhs) const if (op == "+" || op == "-"){ return mixin("R(x " ~ op ~ " rhs.x, y " ~ op ~ "rhs.y, z " ~ op ~ " rhs.z)"); } } ``` but the same error occurs. If I don't use the mixin templates and, instead, I overload the operations into the structures everything works. ```d struct point{ float x, y, z; vec opBinary(string op)(point rhs) const if (op == "-") { return vec(x - rhs.x, y - rhs.y, z - rhs.z); } point opBinary(string op)(vec rhs) const if (op == "+") { return point(x + rhs.x, y + rhs.y, z + rhs.z); } } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` Am I doing something wrong or it is impossible to use mixin templates like that? Looks like a compiler bug, since substituting the real methods makes the `mixin template` code compile fine Also, remove the `const`, otherwise the method will word only on `const` instances even if the bug gets fixed ```d mixin template sum(T, R) { R opBinary(string op)(T rhs) const if (op == "+"){ return R(x + rhs.x, y + rhs.y, z + rhs.z); } } mixin template diff(T, R) { R opBinary(string op)(T rhs) const if (op == "-") { return R(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin diff!(point, vec); mixin sum!(vec, point); } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1.opBinary!"-"(p2); // made - explicit vec v2 = {2,-1,0}; point p3 = p1.opBinary!"+"(v2); // made + explicit }
Re: How to print or check if a string is "\0" (null) terminated in the D programming language?
On Wednesday, 6 April 2022 at 08:55:43 UTC, BoQsc wrote: I have a feeling that some parts of my code contains unterminated strings and they do overflow into other string [...] If you suspect overflow, you can try string wrapping.
Mixin Templates and Operators
I have two structs, point and vec, in which I want to implement some arithmetic operations. The operations are: ``` point - point = vec point + vec = point ``` Using mixin templates the code compiles but calling the operations in the main causes an "incompatible type" Error: ```d mixin template sum(T, R) { R opBinary(string op)(T rhs) const if (op == "+"){ return R(x + rhs.x, y + rhs.y, z + rhs.z); } } mixin template diff(T, R) { R opBinary(string op)(T rhs) const if (op == "-") { return R(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin diff!(point, vec); mixin sum!(vec, point); } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` The output of `dub run` is ``` Performing "debug" build using /usr/bin/dmd for x86_64. query ~master: building configuration "application"... source/app.d(27,13): Error: incompatible types for `(p1) - (p2)`: both operands are of type `point` source/app.d(30,15): Error: incompatible types for `(p1) + (v2)`: `point` and `vec` /usr/bin/dmd failed with exit code 1. ``` I tried to implement a single template: ```d mixin template sumDiff(T, R){ R opBinary(string op)(T rhs) const if (op == "+" || op == "-"){ return mixin("R(x " ~ op ~ " rhs.x, y " ~ op ~ "rhs.y, z " ~ op ~ " rhs.z)"); } } ``` but the same error occurs. If I don't use the mixin templates and, instead, I overload the operations into the structures everything works. ```d struct point{ float x, y, z; vec opBinary(string op)(point rhs) const if (op == "-") { return vec(x - rhs.x, y - rhs.y, z - rhs.z); } point opBinary(string op)(vec rhs) const if (op == "+") { return point(x + rhs.x, y + rhs.y, z + rhs.z); } } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` Am I doing something wrong or it is impossible to use mixin templates like that?
Re: How to print or check if a string is "\0" (null) terminated in the D programming language?
On Wednesday, 6 April 2022 at 08:55:43 UTC, BoQsc wrote: I have a feeling that some parts of my code contains unterminated strings and they do overflow into other string that is to be combined. I'd like to take a look at strings, analyse them manually and see if any of them end up terminated or not. Please provide any relevant examples of how you do this. In general, you shouldn't do that. In D, a `string`, `wstring` and `dstring` are slices of corresponding character types, and are *not* null-terminated (and in fact can contain 0 within their representation). However, as Andrea Fontana points out, string literals are null-terminated (but note that the terminator itself isn't included in a `string` initialized with such a literal), and also convert to pointers - these two properties allow using them as arguments to C functions. Thus, since null terminator isn't normally included as part of a string, you'd have to read past array bounds to check if there's a 0 there, and doing so leads to undefined behavior. In fact, you should simply assume that any D string you encounter is not null-terminated. And if you want to ensure you're always passing around null-terminated strings, you should either use the greedy allocating functions such as `toStringz`, or perhaps make your own type that always allocates extra space for a 0.
Re: How to print or check if a string is "\0" (null) terminated in the D programming language?
On Wednesday, 6 April 2022 at 08:55:43 UTC, BoQsc wrote: I have a feeling that some parts of my code contains unterminated strings and they do overflow into other string that is to be combined. I'd like to take a look at strings, analyse them manually and see if any of them end up terminated or not. Please provide any relevant examples of how you do this. string literals are zero-terminated in d. If you need to pass a D string to a C function use toStringz() https://dlang.org/library/std/string/to_stringz.html
How to print or check if a string is "\0" (null) terminated in the D programming language?
I have a feeling that some parts of my code contains unterminated strings and they do overflow into other string that is to be combined. I'd like to take a look at strings, analyse them manually and see if any of them end up terminated or not. Please provide any relevant examples of how you do this.