How is opEquals used in toHash

2021-05-18 Thread PinDPlugga via Digitalmars-d-learn
In the solution to one of the exercises in Programming in D the 
unittests fail with respect to the toHash implementation.


Here is a link to the full solution provided:
https://run.dlang.io/gist/99ddf791f86aaa9d333d032166aadcb9?args=-unittest%20-main

and the link to the relevant section in the book:
https://ddili.org/ders/d.en/object.html

so while the unittest for equality passes, the next test with 
`in` is where the failure occurs:

```D
// ...
assert(area1 == area2);// Passes

double[TriangularArea] areas;
areas[area1] = 1.25;

assert(area2 in areas); // Fails
// ...
```

the issue must be with the toHash function given
``` D
override size_t toHash() const {
/* Since the 'points' member is an array, we can take
 * advantage of the existing toHash algorithm for
 * array types. */
return typeid(points).getHash();
}
```

I looked into the object library documentation and saw that the 
template getHash calls hashOf which calls 
core.internal.hash.hashOf etc.


But what I do not understand is why opEquals is necessary and 
where in the implementation of toHash it plays its role? Since 
area1 and area2 have different static arrays of Points I 
understand why `typeid(points).getHash()` would produce 
different values for each, but it seems like the opEquals should 
play a part in making them produce the same hash.


Re: ref struct member function

2021-05-14 Thread PinDPlugga via Digitalmars-d-learn

On Thursday, 13 May 2021 at 19:48:44 UTC, Ali Çehreli wrote:
I was writing this example that shows a use case for the 
problem (marked with BUG below):

```D
struct Fraction {
auto n = 0L;
auto d = 1L;

// ... other bits ...

ref Fraction reduce() {
  import std.numeric : gcd;

  // v = gcd(n, d);
  // if (v > 1) {
  //   n /= v;
  //   d /= v;
  // }

  return this;
}

// ... etc ...
}

ref foo() {
  import std.stdio : writeln;
  auto f = Fraction(3, 9);

  // BUG: Returns reference to an object on the stack
  return f.reduce();
}

void main() {
  // Refers to a temporary (it would be a copy without the &)
  auto f = ();

  // Do some unrelated things hoping that space for dead 
objects on

  // the stack will be reused.
  import std.stdio;
  import std.random;
  writeln("doing something else: ", uniform(0, 6));

  writeln(f.d); // Access dead and overwritten object (does NOT 
print

// 9 on my system)
}
```
Putting 'return' where Steve shows makes the compiler guard us 
against this misuse and the program thankfully does not compile.


Ali


Hi thank you both for your answers. I had understood from an 
earlier chapter how this could introduce a bug, but I was 
confused because the warning suggests attaching ```return``` to 
the parameter, which is empty in the declaration.


So my next question would be how come ref based operator 
overloads are not labelled as return and do not show this warning?


``` D
struct Fraction {
auto n = 0L;
auto d = 1L;

ref Fraction opUnary(string op)()
if (op == "++") {
n += d;
return this;
}
}

ref Fraction foo() {
auto f = Fraction(1, 3);

// Same bug as with reduce
return ++f;
}
```


ref struct member function

2021-05-13 Thread PinDPlugga via Digitalmars-d-learn
Hi I am working through Programming in D. In one exercise I have 
a helper function in a struct


```D
struct Fraction {
auto n = 0L;
auto d = 1L;

// ... other bits ...

ref Fraction reduce() {
  import std.numeric : gcd;

  v = gcd(n, d);
  if (v > 1) {
n /= v;
d /= v;
  }

  return this;
}

// ... etc ...
}

void main() {
  import std.stdio : writeln;
  auto f = Fraction(3, 9);
  writeln(f.reduce());
}
```

This works but issues a deprecation warning:
```
onlineapp.d(30): Deprecation: returning `this` escapes a 
reference to parameter `this`
onlineapp.d(30):perhaps annotate the parameter with 
`return`

Fraction(1, 3)
```

I found several other ways to make this work without the 
warnings, but I am wondering how to make this particular case 
work, or if it is not a recommended way, what the proper way 
would be.


Calling readln() after readf

2021-04-24 Thread PinDPlugga via Digitalmars-d-learn
I didn't want to necropost, but I ran into the same behaviour as 
in this post:

https://forum.dlang.org/post/yfybveovbknvvxmio...@forum.dlang.org
and was just curious to understand it better.

If I call readln() after having previously called readf(), it 
does not behave as expected:

```d
import std.stdio, std.string;

void main()
{
write("Please enter a number: ");
double number;
readf(" %s", number);

write("Please enter a string: ");
string input = strip(readln());

writefln!("number: %s --- string: %s")(number, input);
}
```
Gives me the following:
```
Please enter a number: 1
Please enter a string: number: 1  string:
```
I know I can get this to work replacing the `strin(readln())` 
with `readf(" %s\n", input)`, but I also found if I just call 
`strip(readln())` an extra time this worked as well, but what is 
confusing to me is if I have multiple readf's I still only need 
to call readln one extra time to get it to work as expected:

```d
import std.stdio, std.string;

void main()
{
write("Please enter a number: ");
double number1;
readf(" %s", number1);
write("Please enter a number: ");
double number2;
readf(" %s", number2);

// Handle what should be two \n's from readf?
string input = strip(readln());

// Continue as normal
write("Please enter a string: ");
input = strip(readln());

writefln!("number1: %s --- number2: %s --- string: %s")
(number1, number2, input);
}
```
And this works.
```
Please enter a number: 1
Please enter a number: 2
Please enter a string: hello
number1: 1 --- number2: 2 --- string: hello
```
Could anyone help explain this to me, and also is there a better 
way to handle this when wanting to use a mix of readf and readln?