August 19, 2022

On Friday, 19 August 2022 at 18:57:25 UTC, Hipreme wrote:

>

On Friday, 19 August 2022 at 16:34:59 UTC, Basile B. wrote:

>

On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:

>

[...]

It's not a mistake, default initialization in D is not designed to be an initialization substitute, it's designed in a way that missing initialization is easily detectable but not UB. However, thruth is that this only works for character and floating point types.

Changing that design would require a DIP I think.

Well, it is used as initialization substitute, if wasn't meant to be a substitute, not initializing a variable should be a compilation error. [...]

I know it is used as substitute but people writing in D should keep in mind that
this is not the spirit of default init.

August 19, 2022

On Friday, 19 August 2022 at 18:04:46 UTC, bachmeier wrote:

>

On Friday, 19 August 2022 at 17:14:35 UTC, Steven Schveighoffer wrote:

>

I also would prefer that all floats/doubles default to 0 instead of NaN.

It would be awful to choose an arbitrary, often incorrect value in order to give the appearance that your program is running.

Any default value is an incorrect value unless it by luck happens to be what the programmer intended it to be. So while zero will often be incorrect I would argue that NaN is almost guaranteed to be incorrect.

And here's the thing, you find some numerical code you've written and change some variable to zero init in instead of whatever it was. Your program wont appear to run properly, it'll give incorrect results, things wont work.

There's this whole fallacy underpinning the default to NaN argument that using zero init will somehow leave programming appearing to run fine with no obvious problems.

its nonsense.

>

It would be absurd to silently set the value of z to 1.0 in this code:

double w;
double z = w*2.5 + 1;

Defaulting to 0 is no better than defaulting to a random number.

What's absurd that the whole point of using NaN as an init value is to catch a bug that could much more easily be caught by requiring explicit initialisation of floats.

double w; // compiler says NO!

August 19, 2022
On 8/19/2022 9:34 AM, Basile B. wrote:
> It's not a mistake, default initialization in D is not designed to be an initialization substitute, it's designed in a way that missing initialization is easily detectable but not UB.

The idea is if you're looking at code:

    double d;

is `d` expected to be initialized to 0.0, or did the programmer just forget to initialize it? D removes that ambiguity.
August 19, 2022
On 8/19/2022 10:14 AM, Steven Schveighoffer wrote:
> ```c
> ReallyLargeStruct foo = { 0 };
> ```

D allows the setting of the default initializer for fields of a struct.
August 19, 2022
On 8/19/2022 12:09 PM, Steven Schveighoffer wrote:
> But it defaults to a completely useless value (NaN).

It is not useless. NaN's have many uses, one of which is to not have silent bugs where you forgot to initialize a double.

> This is unexpected, and commonly leads to hours of head-scratching (see Adam's Ruppe's 2020 live coding session, where he couldn't figure out for much of the stream why his game wasn't working).

It's fewer hours then tracking down why it is 0 instead of 6, because 0 doesn't leave a trail.


> D used default values to prevent errors in not initializing values, but default initialization to a very commonly-expected value turns to be incredibly useful.

I've lost days in debugging issues with forgetting to initialize a variable.


> The design choices for float/double were made based on the fact that a value that means "this isn't initialized" existed. It didn't for int, so meh, 0 was chosen. Walter could have easily have just chosen int.min or something, and then we would possibly not ever be used to it. But now we are used to it, so it has become irksome that doubles/floats are the outlier here.

If there was a NaN value for int, I would have used it as the default. int.min is not really a NaN.

The NaN value for char is 0xFF, and for pointers is null. Both work well. (0xFF is specified as an illegal code point in Unicode.) It's integers that are the outliers :-)

August 20, 2022

On Friday, 19 August 2022 at 23:11:35 UTC, claptrap wrote:

>

double w; // compiler says NO!

The compiler should prohibit such statements.

August 19, 2022

On 8/19/22 9:01 PM, Walter Bright wrote:

>

On 8/19/2022 12:09 PM, Steven Schveighoffer wrote:

>

But it defaults to a completely useless value (NaN).

It is not useless. NaN's have many uses, one of which is to not have silent bugs where you forgot to initialize a double.

Knowing that somewhere, in some code, someone didn't initialize a double, is not useful. And that's if you notice it.

In fact, NaN creates silent bugs.

> >

This is unexpected, and commonly leads to hours of head-scratching (see Adam's Ruppe's 2020 live coding session, where he couldn't figure out for much of the stream why his game wasn't working).

It's fewer hours then tracking down why it is 0 instead of 6, because 0 doesn't leave a trail.

That's not what happens. You see, when you do DrawSquare(x, y), nothing happens. No exception thrown, no "Bad Square" drawn to the screen, it's like your function didn't get called. You start questioning just about every other aspect of your code (Am I calling the function? Is the library calling my function? Is there a bug in the library?). You don't get any indication that x is NaN. Whereas, if it's zero, and that's wrong, you see a square in the wrong spot, and fix it.

In other words, NaN is silent. You can't even assert(x != double.init). You have to use an esoteric function isNaN for that.

But all the code that does expect 0 to be the default would become useful. So there's upsides both ways -- the silent nature of NaN bugs goes away, and now your code doesn't have to always assign a value to a float buried in a struct.

> >

D used default values to prevent errors in not initializing values, but default initialization to a very commonly-expected value turns to be incredibly useful.

I've lost days in debugging issues with forgetting to initialize a variable.

I mostly do not initialize variables when I know the default value is correct.

But even having NaN as a default is classes above C where it not only might not have the correct value, the value can be garbage. That can cause days of searching.

> >

The design choices for float/double were made based on the fact that a value that means "this isn't initialized" existed. It didn't for int, so meh, 0 was chosen. Walter could have easily have just chosen int.min or something, and then we would possibly not ever be used to it. But now we are used to it, so it has become irksome that doubles/floats are the outlier here.

If there was a NaN value for int, I would have used it as the default. int.min is not really a NaN.

Why not just require initialization? I'm mostly curious, because I don't think it's possible to do now, but why didn't you do that originally?

>

The NaN value for char is 0xFF, and for pointers is null. Both work well. (0xFF is specified as an illegal code point in Unicode.) It's integers that are the outliers :-)

the default for char is odd, but mostly esoteric. It crops up with things like static char arrays, which are not common. Honestly, having a default of 0 would be better there too, because of C's requirement to null-terminate. But that value isn't terrible (and it doesn't have the problems of NaN, e.g. ++ on it will not just leave it at 0xff).

But the default for pointers being null is perfect. Using a null pointer is immediately obvious since it crashes the program where it is used.

-Steve

August 19, 2022

On 8/19/22 8:49 PM, Walter Bright wrote:

>

On 8/19/2022 10:14 AM, Steven Schveighoffer wrote:

>
ReallyLargeStruct foo = { 0 };

D allows the setting of the default initializer for fields of a struct.

Yes, and then you aren't forced to initialize the big struct. Which is what I did. But if I forget to initialize a float somewhere in there, then it's ruined.

I suppose I can write a unittest to test that it's all zeroes.

But I also find it ironic that you are promoting using the struct's init value as a feature, but not a basic type's init value.

-Steve

August 20, 2022

On Friday, 19 August 2022 at 18:57:25 UTC, Hipreme wrote:

>

Well, it is used as initialization substitute, if wasn't meant to be a substitute, not initializing a variable should be a compilation error.

0, false, null array, etc. are all identities of the "primary" operation on the type, so people intuitively expect them to be the default initial value. I believe that's why most think nan is unnatural.

August 19, 2022
On 8/19/22 06:42, Hipreme wrote:

> that float and double are initialized to `nan`.

I think nan is the right choice. As Walter said, integrals are the outliers because there is not non equivalent for them.

> This is really bad

Although we are all guilty, what is worse is using fundamental types directly. I think the following is a solution to nan being inappropriate e.g. for Distance:

struct initted(T, T initValue) {
  T value = initValue;
  alias value this;
}

alias Distance = initted!(double, 0);

void main() {
  Distance d;  // Not a nan ;)
  d += 1.5;
  d /= 2;
  assert(d == 0.75);
}

However, it is not type-safe enough because one can mix and match Distance with e.g. Temperature, which may not be correct for the program.

Ali