Re: Removing elements from dynamic arrays?

2022-04-06 Thread Siarhei Siamashka via Digitalmars-d-learn
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?

2022-04-06 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2022-04-06 Thread Guillaume Piolat via Digitalmars-d-learn

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?

2022-04-06 Thread Salih Dincer via Digitalmars-d-learn
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

2022-04-06 Thread Adam D Ruppe via Digitalmars-d-learn
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

2022-04-06 Thread Guillaume Piolat via Digitalmars-d-learn

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

2022-04-06 Thread Adam D Ruppe via Digitalmars-d-learn
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

2022-04-06 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2022-04-06 Thread Steven Schveighoffer via Digitalmars-d-learn

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?

2022-04-06 Thread Steven Schveighoffer via Digitalmars-d-learn

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([0] - [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([0] - [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

2022-04-06 Thread Adam D Ruppe via Digitalmars-d-learn
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

2022-04-06 Thread Tejas via Digitalmars-d-learn
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?

2022-04-06 Thread Salih Dincer via Digitalmars-d-learn

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

2022-04-06 Thread francesco.andreetto via Digitalmars-d-learn
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?

2022-04-06 Thread Stanislav Blinov via Digitalmars-d-learn

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?

2022-04-06 Thread Andrea Fontana via Digitalmars-d-learn

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?

2022-04-06 Thread BoQsc via Digitalmars-d-learn
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.