www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Movement against float.init being nan

reply Hipreme <msnmancini hotmail.com> writes:
As someone coming from Java to use D, I find it myself quite 
annoying that float and double are initialized to `nan`.

This is really bad, it is hard to detect for newcomers, there is 
no flag by default to throw an exception when some operation on 
nan is done. It can be misleading if you're not paying a lot of 
attention to what you're doing.

What I suggest is what any sane people would: use 0 as the start 
for float and double. 0 is the most common sense as a starting 
point for everything, and, there are 2 options we could go:


1: Emit a compilation error that every variable must be 
initialized (I thought D were trying to avoid runtime errors)
2: 0 init all types, so, none is actually invalid before use


Even `char` took me as surprise to know it actually starts as 
0xff, I lost a bit of time trying to find that bug because it is 
so common that variables init as zero.

Although the `char` is a bit different beast in terms of breaking 
change, I really *can't see* anyone actually depending that your 
float is being initialized with `nan`, so I really would like to 
know how much people agree with this idea. It is so common to 
stumble on that problem that it is starting to feel as a real 
mistake.
Aug 19 2022
next sibling parent bachmeier <no spam.net> writes:
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:

 What I suggest is what any sane people would: use 0 as the 
 start for float and double. 0 is the most common sense as a 
 starting point for everything, and, there are 2 options we 
 could go:
That would be a disaster. If you're computing a product, 0 is horrible, and there's nothing to suggest you're doing something wrong. At least nan is going to tell you that you've screwed up. The reasonable fix is to either make it a compilation error (my preference) or an error when compiled with a particular flag.
Aug 19 2022
prev sibling next sibling parent reply IGotD- <nise nise.com> writes:
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:
 This is really bad, it is hard to detect for newcomers, there 
 is no flag by default to throw an exception when some operation 
 on nan is done. It can be misleading if you're not paying a lot 
 of attention to what you're doing.
Question: Can the x86 be set to trap when an operation with NaN is detected?
Aug 19 2022
parent Adam D Ruppe <destructionator gmail.com> writes:
On Friday, 19 August 2022 at 13:58:28 UTC, IGotD- wrote:
 Question: Can the x86 be set to trap when an operation with NaN 
 is detected?
Yes, that's called the signaling nan. D actually used to use that for init and it was changed a few years ago: https://forum.dlang.org/thread/nsp1ql$ivu$1 digitalmars.com
Aug 19 2022
prev sibling next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:
 As someone coming from Java to use D, I find it myself quite 
 annoying that float and double are initialized to `nan`.

 This is really bad, it is hard to detect for newcomers, there 
 is no flag by default to throw an exception when some operation 
 on nan is done. It can be misleading if you're not paying a lot 
 of attention to what you're doing.

 What I suggest is what any sane people would: use 0 as the 
 start for float and double. 0 is the most common sense as a 
 starting point for everything, and, there are 2 options we 
 could go:


 1: Emit a compilation error that every variable must be 
 initialized (I thought D were trying to avoid runtime errors)
 2: 0 init all types, so, none is actually invalid before use


 Even `char` took me as surprise to know it actually starts as 
 0xff, I lost a bit of time trying to find that bug because it 
 is so common that variables init as zero.

 Although the `char` is a bit different beast in terms of 
 breaking change, I really *can't see* anyone actually depending 
 that your float is being initialized with `nan`, so I really 
 would like to know how much people agree with this idea. It is 
 so common to stumble on that problem that it is starting to 
 feel as a real mistake.
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.
Aug 19 2022
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/19/22 12:34 PM, Basile B. wrote:
 On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:
 As someone coming from Java to use D, I find it myself quite annoying 
 that float and double are initialized to `nan`.

 This is really bad, it is hard to detect for newcomers, there is no 
 flag by default to throw an exception when some operation on nan is 
 done. It can be misleading if you're not paying a lot of attention to 
 what you're doing.

 What I suggest is what any sane people would: use 0 as the start for 
 float and double. 0 is the most common sense as a starting point for 
 everything, and, there are 2 options we could go:


 1: Emit a compilation error that every variable must be initialized (I 
 thought D were trying to avoid runtime errors)
 2: 0 init all types, so, none is actually invalid before use


 Even `char` took me as surprise to know it actually starts as 0xff, I 
 lost a bit of time trying to find that bug because it is so common 
 that variables init as zero.

 Although the `char` is a bit different beast in terms of breaking 
 change, I really *can't see* anyone actually depending that your float 
 is being initialized with `nan`, so I really would like to know how 
 much people agree with this idea. It is so common to stumble on that 
 problem that it is starting to feel as a real mistake.
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.
This is true, it's not a mistake, it is on purpose. The original idea behind default values is to correct so many mistakes from C where values are not initialized but just "happen" to work until it doesn't. But practically, it is now used as de-facto initialization, it's just too convenient. In that mindset, floats defaulting to NaN are an outlier. However, in my recent efforts to port a decently sized C library to D, one thing I don't have a good answer for is code like: ```c ReallyLargeStruct foo = { 0 }; ``` There just is no equivalent in D. In order to set all fields to 0, I would have to specify a complete layout of the entire thing. This could probably be done via introspection. But I just don't like it even in that case. The easier thing to do is to default the `float` and `double` fields to 0 in the type definition, and then use default initialization to achieve the same. So I think in some cases, it's much nicer to just rely on the default initialization. I also would prefer that all floats/doubles default to 0 instead of NaN. -Steve
Aug 19 2022
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
Shame its not as simple as writing:

foo.tupleof = 0;
Aug 19 2022
prev sibling next sibling parent reply bachmeier <no spam.net> writes:
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. 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.
Aug 19 2022
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/19/22 2:04 PM, 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.
The problem is that most people declare a number like `int x` and expect it to default to 0. Because that's what D does. For a float (number), they expect the same thing. But it defaults to a completely useless value (NaN). 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 would be absurd to silently set the value of `z` to 1.0 in this code:
 
 ```
 double w;
 double z = w*2.5 + 1;
 ```
 
Not absurd at all. if `w` defaults to 0, I would expect `z` to be `2.5 * 0 + 1`. Change it to `int`, and see if it looks absurd to you. You just aren't used to it. 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. 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. -Steve
Aug 19 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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 :-)
Aug 19 2022
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
Aug 19 2022
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/19/2022 8:12 PM, Steven Schveighoffer wrote:
 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.
I don't see how. Any operation with a NaN produces a NaN result. If you've got a NaN result, it can be traced back to its source. This is hard with 0 initialization.
 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.
I don't know why floating point for drawing coordinates? Besides, when I wonder if a function is being called, I put a printf in it. Or set a breakpoint in the debugger. This is routine debugging work. Then I'll look at the values of the parameters. Again, routine. Back in the olden days, I'd have the embedded system click the speaker to see if it entered a function :-)
 In other words, NaN is silent. You can't even `assert(x != double.init)`. You 
 have to use an esoteric function `isNaN` for that.
It is not silent. Every single usage of NaN produces a NaN result. If printing a NaN value, the result is "NaN".
 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.
struct S { float x = 0; }
 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?
Because I've seen what happens with that. The compiler complains about no initializer, and the programmer just puts in "0" to shut up the compiler. He does not make the effort to figure out what it should be initialized to. The reviewer wastes time trying to figure why it is uselessly initialized to zero. This is an especial problem when the initialized value is never used. The reviewer is left wondering if it is a bug. D is designed this way so that explicit initializations to a value are *intentional* rather than a side effect of compiler error messages. This is all part of D's design to encourage writing code that is easier to debug, review and maintain. Even if it takes a little more writing up front.
Aug 19 2022
next sibling parent reply Hipreme <msnmancini hotmail.com> writes:
On Saturday, 20 August 2022 at 05:18:20 UTC, Walter Bright wrote:
 On 8/19/2022 8:12 PM, Steven Schveighoffer wrote:
 [...]
I don't see how. Any operation with a NaN produces a NaN result. If you've got a NaN result, it can be traced back to its source. This is hard with 0 initialization.
 [...]
I don't know why floating point for drawing coordinates? Besides, when I wonder if a function is being called, I put a printf in it. Or set a breakpoint in the debugger. This is routine debugging work. Then I'll look at the values of the parameters. Again, routine. Back in the olden days, I'd have the embedded system click the speaker to see if it entered a function :-)
 [...]
It is not silent. Every single usage of NaN produces a NaN result. If printing a NaN value, the result is "NaN".
 [...]
struct S { float x = 0; }
 [...]
Because I've seen what happens with that. The compiler complains about no initializer, and the programmer just puts in "0" to shut up the compiler. He does not make the effort to figure out what it should be initialized to. The reviewer wastes time trying to figure why it is uselessly initialized to zero. This is an especial problem when the initialized value is never used. The reviewer is left wondering if it is a bug. D is designed this way so that explicit initializations to a value are *intentional* rather than a side effect of compiler error messages. This is all part of D's design to encourage writing code that is easier to debug, review and maintain. Even if it takes a little more writing up front.
Drawing with float is required a lot on modern drawing API. What motivated me doing that post was firstly because I was sending OpenGL NaN coordinates, which resulted in needing a gpu debugger for that. I don't see how easier it is to track a nan. Division by zero causes exception which is the best thing ever. Multiplication produces a zero result, which is pretty obvious to track. If the number does not change you will pretty much print both values and you'll easily find the 0 there.
Aug 20 2022
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/20/2022 6:19 AM, Hipreme wrote:
 I don't see how easier it is to track a nan. Division by zero causes exception 
 which is the best thing ever. Multiplication produces a zero result, which is 
 pretty obvious to track. If the number does not change you will pretty much 
 print both values and you'll easily find the 0 there.
x * NaN => NaN x / NaN => NaN x + NaN => NaN x - NaN => NaN -Nan => NaN cos(NaN) => NaN exp(NaN) => NaN Only a subset of this is true for 0.
Aug 20 2022
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
I forgot to add that 0.0 is such a common floating point value, its erroneous 
use cannot be reliably distinguished from valid uses. Just finding a 0 is not 
good enough, but finding a NaN is.
Aug 20 2022
parent reply claptrap <clap trap.com> writes:
On Sunday, 21 August 2022 at 03:41:55 UTC, Walter Bright wrote:
 I forgot to add that 0.0 is such a common floating point value, 
 its erroneous use cannot be reliably distinguished from valid 
 uses. Just finding a 0 is not good enough, but finding a NaN is.
This is a complete misrepresentation. It's not that you find 0s and say oh well it shouldn't be zero here. It's that your results are wrong, stuff on screen isn't where it should be, your data plots are off, it's not doing what it should be etc.. If you're doing some numerical computation and you cant tell when the results are wrong then you almost always doing you're doing something wrong anyway. The point is, at least in my experience, and I do a lot of DSP and statistics stuff, you know the result is wrong and you just chase it backwards, its the same process whether it's a NaN or just a wrong result. And the fact is if you'd just disallowed default initialisation it would have caught this bug every time for me, and I wouldn't have just stuck zero in, because the bug is that I forgot to set the value, not that I didn't know what it was. So from my experience the rational is based on two fallacies. 1. That using zero as default init would hide the bug. 2. That people will just stick zero in because they don't know what it should be.
Aug 21 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/21/2022 2:01 AM, claptrap wrote:
 So from my experience the rational is based on two fallacies.
 
 1. That using zero as default init would hide the bug.
If the computed answer is 1.7239 rather than 1.7230 because of an erroneous 0 input, how would you know it is wrong? But if the computed answer is NaN, you *know* it is wrong.
 2. That people will just stick zero in because they don't know what it should
be.
I know *you* wouldn't do it (I wouldn't either), but like I wrote, I've seen it happen. I've also seen cases of: double x = 0; ... no uses of x ... x = 5; ... where the initialization was put in to shut the compiler up. But to one unfortunate enough to be reviewing unfamiliar code, this double initialization has a smell about it - which initialization is the correct one? Why was it initialized to 0 when that makes no sense for the algorithm? It is also why if it is desirable for a variable to be uninitialized, the double x = void; form must be used, as that is highly unlikely to be written by accident. I.e. this is all designed to encourage the programmer to write code intentionally, rather than accidentally. BTW, I've done user support (helping them debug problems with their code) for 40 years now. I've talked a lot with team managers about what problems they experience with code. A lot of D's unusual features come from this experience.
Aug 21 2022
parent claptrap <clap trap.com> writes:
On Sunday, 21 August 2022 at 15:26:54 UTC, Walter Bright wrote:
 On 8/21/2022 2:01 AM, claptrap wrote:
 So from my experience the rational is based on two fallacies.
 
 1. That using zero as default init would hide the bug.
If the computed answer is 1.7239 rather than 1.7230 because of an erroneous 0 input, how would you know it is wrong? But if the computed answer is NaN, you *know* it is wrong.
Go through all the math functions in phobos and see what would happen if you zeroed out some random local variables, you wont get results that are a tiny fraction of a percent out, it'll be way off 99 times out of 100. Im not saying it cant happen, but that it's vastly exaggerated how likely it is that an erroneous zero init wont be obvious.
 2. That people will just stick zero in because they don't know 
 what it should be.
I know *you* wouldn't do it (I wouldn't either), but like I wrote, I've seen it happen. I've also seen cases of: double x = 0; ... no uses of x ... x = 5; ... where the initialization was put in to shut the compiler up. But to one unfortunate enough to be reviewing unfamiliar code, this double initialization has a smell about it - which initialization is the correct one? Why was it initialized to 0 when that makes no sense for the algorithm?
Id still rather have the compiler error, that is more helpful to me that preventing somebody else writing crappy but *working* code.
Aug 21 2022
prev sibling next sibling parent reply Dark Hole <dark.hole1 yandex.ru> writes:
On Sunday, 21 August 2022 at 03:25:57 UTC, Walter Bright wrote:
 On 8/20/2022 6:19 AM, Hipreme wrote:
 I don't see how easier it is to track a nan. Division by zero 
 causes exception which is the best thing ever. Multiplication 
 produces a zero result, which is pretty obvious to track. If 
 the number does not change you will pretty much print both 
 values and you'll easily find the 0 there.
x * NaN => NaN x / NaN => NaN x + NaN => NaN x - NaN => NaN -Nan => NaN cos(NaN) => NaN exp(NaN) => NaN Only a subset of this is true for 0.
Imagine, we have nullable int (int?) in language. ```d int? x => null x * null => null x / null => null x + null => null x - null => null -cast(int?)null => null ``` Seems like perfect solution (except performance costs)
Aug 21 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 21 August 2022 at 11:13:02 UTC, Dark Hole wrote:
 Imagine, we have nullable int (int?) in language.

 ```d
 int? x => null
 x * null => null
 x / null => null
 x + null => null
 x - null => null
 -cast(int?)null => null
 ```

 Seems like perfect solution (except performance costs)
We have this in the standard library already: import std.checkedint; Checked!(int, WithNaN) n; assert(n.isNaN); assert((123 * n).isNaN); assert((123 / n).isNaN); assert((123 + n).isNaN); assert((123 - n).isNaN); assert((-n).isNaN);
Aug 21 2022
parent reply Dark Hole <dark.hole1 yandex.ru> writes:
On Sunday, 21 August 2022 at 13:47:43 UTC, Paul Backus wrote:
 On Sunday, 21 August 2022 at 11:13:02 UTC, Dark Hole wrote:
 Imagine, we have nullable int (int?) in language.

 ```d
 int? x => null
 x * null => null
 x / null => null
 x + null => null
 x - null => null
 -cast(int?)null => null
 ```

 Seems like perfect solution (except performance costs)
We have this in the standard library already: import std.checkedint; Checked!(int, WithNaN) n; assert(n.isNaN); assert((123 * n).isNaN); assert((123 / n).isNaN); assert((123 + n).isNaN); assert((123 - n).isNaN); assert((-n).isNaN);
My point is making this by default for all primitive types. This will be consistent and simple: ```d bool x; // Error, use bool? or init it something meaningful struct Foo { bool x; } // Error too ``` So we have no problem "programmers make meaningless 0" and have no problem to determine init for most of types.
Aug 21 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 8/21/22 16:09, Dark Hole wrote:
 
 My point is making this by default for all primitive types. This will be 
 consistent and simple:
 ```d
 bool x; // Error, use bool? or init it something meaningful
 struct Foo { bool x; } // Error too
 ```
 So we have no problem "programmers make meaningless 0" and have no 
 problem to determine init for most of types.
I think a better way to approach this problem is to have a language where people are not tempted to declare a variable into which they have no sensible value to put in the first place. If you have no value at a given point in the program, you should not need a variable to hold one.
Oct 08 2023
parent monkyyy <crazymonkyyy gmail.com> writes:
On Monday, 9 October 2023 at 00:03:24 UTC, Timon Gehr wrote:
 On 8/21/22 16:09, Dark Hole wrote:
 
 My point is making this by default for all primitive types. 
 This will be consistent and simple:
 ```d
 bool x; // Error, use bool? or init it something meaningful
 struct Foo { bool x; } // Error too
 ```
 So we have no problem "programmers make meaningless 0" and 
 have no problem to determine init for most of types.
I think a better way to approach this problem is to have a language where people are not tempted to declare a variable into which they have no sensible value to put in the first place. If you have no value at a given point in the program, you should not need a variable to hold one.
~~definitely not bumping this thread to keep it alive~~ Im pretty sure that declaration before use needs to be a thing cause compilers are still bad at knowing where memory sure go and I need my goto and global scope variables.
Oct 09 2023
prev sibling parent drug007 <drug2004 bk.ru> writes:
On 8/21/22 06:25, Walter Bright wrote:
 On 8/20/2022 6:19 AM, Hipreme wrote:
 I don't see how easier it is to track a nan. Division by zero causes 
 exception which is the best thing ever. Multiplication produces a zero 
 result, which is pretty obvious to track. If the number does not 
 change you will pretty much print both values and you'll easily find 
 the 0 there.
x * NaN => NaN x / NaN => NaN x + NaN => NaN x - NaN => NaN -Nan => NaN cos(NaN) => NaN exp(NaN) => NaN Only a subset of this is true for 0.
I totally agree that NaN is really useful because makes it easier to find the reason for the NaN result
Aug 21 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/20/2022 6:19 AM, Hipreme wrote:
 Drawing with float is required a lot on modern drawing API.
I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Aug 20 2022
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:
 On 8/20/2022 6:19 AM, Hipreme wrote:
 Drawing with float is required a lot on modern drawing API.
I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Graphics APIs have been using floating point for decades now. GPUs are optimized for it. You'll still see 2D APIs around now and again with an integer-based public API, but internally they're sending floats to the GPU.
Aug 20 2022
next sibling parent jordan4ibanez <jordan4ibanez002 gmail.com> writes:
On Sunday, 21 August 2022 at 06:23:39 UTC, Mike Parker wrote:
 On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:
 On 8/20/2022 6:19 AM, Hipreme wrote:
 Drawing with float is required a lot on modern drawing API.
I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Graphics APIs have been using floating point for decades now. GPUs are optimized for it. You'll still see 2D APIs around now and again with an integer-based public API, but internally they're sending floats to the GPU.
Yes this is exactly the truth. GLSL has integer, but no matter what you do, no matter how hard you try, When you go to the final output it will always be sent out as a floating point with ``gl_Position``.
Aug 20 2022
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/20/2022 11:23 PM, Mike Parker wrote:
 On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:
 On 8/20/2022 6:19 AM, Hipreme wrote:
 Drawing with float is required a lot on modern drawing API.
I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Graphics APIs have been using floating point for decades now. GPUs are optimized for it. You'll still see 2D APIs around now and again with an integer-based public API, but internally they're sending floats to the GPU.
I guess I stand corrected :-)
Aug 21 2022
prev sibling next sibling parent IGotD- <nise nise.com> writes:
On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:
 I find this surprising. My experience with floating point 
 coordinates is you can never quite get the pixels aligned, due 
 to rounding problems.
That's the whole point. In graphics and especially 3D graphics use floating point in order to achieve sub pixel accuracy. That means it uses the fractional part to draw more accurate lines for example. It can be used for anti antialiasing calculations and so on. Without subpixel accuracy we would experience more "steppy" movement in 3D games for example. This can be observed in early 3D games which only used integer calculations.
Aug 21 2022
prev sibling parent claptrap <clap trap.com> writes:
On Sunday, 21 August 2022 at 03:26:55 UTC, Walter Bright wrote:
 On 8/20/2022 6:19 AM, Hipreme wrote:
 Drawing with float is required a lot on modern drawing API.
I find this surprising. My experience with floating point coordinates is you can never quite get the pixels aligned, due to rounding problems.
Modern drawing APIs have sub pixel positioning & antialising. GDI+ had that, at that was XP i think, so what 20 years ago maybe?
Aug 21 2022
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Saturday, 20 August 2022 at 05:18:20 UTC, Walter Bright wrote:
 Because I've seen what happens with that. The compiler 
 complains about no initializer, and the programmer just puts in 
 "0" to shut up the compiler. He does not make the effort to 
 figure out what it should be initialized to. The reviewer 
 wastes time trying to figure why it is uselessly initialized to 
 zero.
On the other hand, the programmer could explicitly initialise the variable to `float.nan`. The problem is that so few people coming from other languages know that trick. D educates us, making me annoyed when other languages use zero as the default and force me to explicitly initialise to NaN :).
Aug 20 2022
prev sibling next sibling parent reply Nick Treleaven <nick geany.org> writes:
On Saturday, 20 August 2022 at 03:12:43 UTC, Steven Schveighoffer 
wrote:
 You can't even `assert(x != double.init)`. You have to use an 
 esoteric function `isNaN` for that.
Actually, you can use `is`: ```d static assert(float() is float.nan); ``` From the spec:
 For struct objects and floating point values, identity is 
 defined as the bits in the operands being identical.
I'm making a pull to add a spec example so it's more obvious.
Aug 20 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Saturday, 20 August 2022 at 10:26:08 UTC, Nick Treleaven wrote:
 On Saturday, 20 August 2022 at 03:12:43 UTC, Steven 
 Schveighoffer wrote:
 You can't even `assert(x != double.init)`. You have to use an 
 esoteric function `isNaN` for that.
Actually, you can use `is`: ```d static assert(float() is float.nan); ```
That works for float.init specifically, but if you've done some operation on it and ended up with a nan, that will not necessarily be true since nans come in several bit patterns.
Aug 20 2022
next sibling parent reply Nick Treleaven <nick geany.org> writes:
On Saturday, 20 August 2022 at 11:51:13 UTC, Adam D Ruppe wrote:
 On Saturday, 20 August 2022 at 10:26:08 UTC, Nick Treleaven 
 wrote:
 On Saturday, 20 August 2022 at 03:12:43 UTC, Steven 
 Schveighoffer wrote:
 You can't even `assert(x != double.init)`. You have to use an 
 esoteric function `isNaN` for that.
Actually, you can use `is`: ```d static assert(float() is float.nan); ```
That works for float.init specifically, but if you've done some operation on it and ended up with a nan, that will not necessarily be true since nans come in several bit patterns.
Then compare it with real.nan - smaller types will be promoted to real: ```d static assert(float() is real.nan); static assert(double() is real.nan); static assert(real() is real.nan); ```
Aug 20 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Saturday, 20 August 2022 at 12:02:17 UTC, Nick Treleaven wrote:
 Then compare it with real.nan - smaller types will be promoted 
 to real:
It isn't about size, but rather the nans can come in different forms. Consider: --- void main() { float f = 7.0; f /= 0; import core.stdc.stdio; printf("%d\n", *cast(int*)&f); if(f is float.init) printf("nan\n"); } --- That's a different nan than the float.init pattern. I don't know if you can start with a float.init and come up with a different pattern though, but i expect you can.
Aug 20 2022
parent reply Nick Treleaven <nick geany.org> writes:
On Saturday, 20 August 2022 at 12:53:28 UTC, Adam D Ruppe wrote:
 ---
 void main() {
         float f = 7.0;
         f /= 0;
         import core.stdc.stdio;
         printf("%d\n", *cast(int*)&f);
         if(f is float.init)
                 printf("nan\n");
 }
 ---

 That's a different nan than the float.init pattern. I don't 
 know if you can start with a float.init and come up with a 
 different pattern though, but i expect you can.
Thanks. The above is infinity though. f = 1.0; f /= 0; assert(f is f.infinity); This produces a different NaN: float f = 0; f /= 0; assert(f is f.nan); //fails
Aug 20 2022
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Saturday, 20 August 2022 at 13:06:49 UTC, Nick Treleaven wrote:
 Thanks. The above is infinity though.
oh yeah i forgot about that rule
 This produces a different NaN:
yes, thanks!
Aug 20 2022
prev sibling parent reply IGotD- <nise nise.com> writes:
On Saturday, 20 August 2022 at 13:06:49 UTC, Nick Treleaven wrote:
 Thanks. The above is infinity though.

 	f = 1.0;
 	f /= 0;
 	assert(f is f.infinity);

 This produces a different NaN:

 	float f = 0;
 	f /= 0;
 	assert(f is f.nan); //fails
I never understood why the IEEE standard decided to include infinity. What were they trying to achieve? Indeterminate maths with floating point?
Aug 20 2022
parent Paul Backus <snarwin gmail.com> writes:
On Saturday, 20 August 2022 at 18:59:40 UTC, IGotD- wrote:
 I never understood why the IEEE standard decided to include 
 infinity. What were they trying to achieve? Indeterminate maths 
 with floating point?
I was curious about this too, so I did some searching. The Wikipedia page on floating-point arithmetic has a section titled "IEEE 754 design rationale" [1], which cites as one of its sources "Why do we need a floating-point arithmetic standard?" [2], a 1981 paper by William Kahan, one of the designers of IEEE 754. In that paper (on page 31), Kahan gives the following rationale for including values like NaN and infinities:
 the proposed standard specifies rules for creating and 
 manipulating sym-
 bols like ±0, ±∞ and NaN – the symbol “NaN ” stands for “Not a 
 Number”.
 These rules are designed so that a programmer may frequently 
 omit tests and
 branches that were previously obligatory because computers 
 treated exceptions
 in unpredictable or capricious ways.
 [...]
 At the
 same time as NaN is created a flag called Invalid Operation is 
 raised. Subse-
 quently the calling program may infer either from this flag or 
 from the NaN that
 an emergency arose and may cope with it automatically rather 
 than abort
So the point is to simplify error handling, and to allow error handling to be deferred. [1] https://en.wikipedia.org/wiki/Floating-point_arithmetic#IEEE_754_design_rationale [2] https://people.eecs.berkeley.edu/~wkahan/ieee754status/why-ieee.pdf
Aug 20 2022
prev sibling next sibling parent Nick Treleaven <nick geany.org> writes:
On Saturday, 20 August 2022 at 11:51:13 UTC, Adam D Ruppe wrote:
 On Saturday, 20 August 2022 at 10:26:08 UTC, Nick Treleaven 
 wrote:
 On Saturday, 20 August 2022 at 03:12:43 UTC, Steven 
 Schveighoffer wrote:
 You can't even `assert(x != double.init)`. You have to use an 
 esoteric function `isNaN` for that.
Actually, you can use `is`: ```d static assert(float() is float.nan); ```
That works for float.init specifically, but if you've done some operation on it and ended up with a nan, that will not necessarily be true since nans come in several bit patterns.
Sorry, so there are other kinds of NaN than T.nan? How do you produce them? `0F/0F is float.nan` is true.
Aug 20 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/20/2022 4:51 AM, Adam D Ruppe wrote:
 That works for float.init specifically, but if you've done some operation on
it 
 and ended up with a nan, that will not necessarily be true since nans come in 
 several bit patterns.
I.e. a "payload" can be put in the mantissa bits of a NaN, which can be used to provide more information about the NaN. I've never seen anyone use this, though, but someone might, so isNaN() is the robust approach.
Aug 20 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/20/22 20:44, Walter Bright wrote:

 I.e. a "payload" can be put in the mantissa bits of a NaN, which can be
 used to provide more information about the NaN.
I think it is called "nan boxing."
 I've never seen anyone
 use this, though, but someone might
I heard about it either at a meetup or at a DConf. The speaker was explaining that exact technique. Ali
Aug 20 2022
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/20/2022 10:03 PM, Ali Çehreli wrote:
 On 8/20/22 20:44, Walter Bright wrote:
 
  > I.e. a "payload" can be put in the mantissa bits of a NaN, which can be
  > used to provide more information about the NaN.
 
 I think it is called "nan boxing."
BTW, this influences code generation, too. For example: x = 0; y = NaN; z = x + y; z gets assigned a NaN. But which NaN? The NaN that was assigned to x. I.e. the specific NaN values get propagated.
Aug 21 2022
prev sibling parent reply mw <m g.c> writes:
On Sunday, 21 August 2022 at 05:03:43 UTC, Ali Çehreli wrote:
 On 8/20/22 20:44, Walter Bright wrote:

 I.e. a "payload" can be put in the mantissa bits of a NaN,
which can be
 used to provide more information about the NaN.
I think it is called "nan boxing."
 I've never seen anyone
 use this, though, but someone might
I heard about it either at a meetup or at a DConf. The speaker was explaining that exact technique.
Just learnt from here: https://github.com/Robert-van-Engelen/tinylisp/issues/12#issuecomment-1752142467
 Another question I want ask is: the NaN boxing trick is OK, 
 but why it's needed here (for education purpose Lisp 
 implementation, this trick I think actually distracted 
 learners from learning Lisp)? Why cannot we just use bit 
 fields or a small struct as tagged union? Also by using NaN 
 boxing, are we actually wasting 13 bits for each double?
Lots of modern PL implementations use NaN boxing instead of tagged structs/unions. Nothing gets wasted, because a cell has to be a fixed size anyway, which is the larger size of all possible values it can hold. Adding a tag therefore makes the cell structure larger by a byte, at least, to hold a tag. That also makes addressing less efficient, since cells are no longer guaranteed to be 32 bit aligned (or the tag has to be 32 bits, which wasts more bits).
I think I understand it now, the benefits of using NaN boxing is that: in a 64-bit double all the doubles are still fully represented use 48 bit as pointer can still address 262,144 GB memory, that is good enough for any computer today only integer's range gets shrunk: from 64-bit to 48-bit (49 with sign bit depends on if we choose to use it), that's good for most purpose, and if one really need > 48-bit integer type, then use the fat BigInt (class / struct) then (which will be treated as object pointer type). (1) and (3) means all the scalar types are stored as scalar, not pointers to some other representations. That's very compact design indeed.
Oct 08 2023
parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/8/2023 12:47 PM, mw wrote:
 That's very compact design indeed.
Interestingly, the nan boxing in tinylisp exposed a subtle code gen problem with dmd (fixed now).
Oct 25 2023
prev sibling parent reply Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Saturday, 20 August 2022 at 03:12:43 UTC, Steven Schveighoffer 
wrote:
 In other words, NaN is silent. You can't even `assert(x != 
 double.init)`. You have to use an esoteric function `isNaN` for 
 that.
I had some fun with `isNaN` the other day. We used it to check for initialisation in an access function to cache an expensive computation. This worked brilliantly until we noticed a malfunction in the release version. It took a while until I realised that I had given the LDC `fastmath` option to the release build, which assumes NaN does not occur, which makes `isNaN` misbehave. What I learned from this is to not use this flag globally, and add select attributes to select functions instead. And instead of using NaN I now use `std.typecons.Nullable` to signal a dirty cache. — Bastiaan.
Aug 22 2022
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Monday, 22 August 2022 at 20:29:57 UTC, Bastiaan Veelo wrote:
 On Saturday, 20 August 2022 at 03:12:43 UTC, Steven 
 Schveighoffer wrote:
 In other words, NaN is silent. You can't even `assert(x != 
 double.init)`. You have to use an esoteric function `isNaN` 
 for that.
I had some fun with `isNaN` the other day. We used it to check for initialisation in an access function to cache an expensive computation. This worked brilliantly until we noticed a malfunction in the release version. It took a while until I realised that I had given the LDC `fastmath` option to the release build, which assumes NaN does not occur, which makes `isNaN` misbehave.
Is there a simple example of this behavior?
Aug 22 2022
parent reply Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Monday, 22 August 2022 at 22:11:23 UTC, jmh530 wrote:
 On Monday, 22 August 2022 at 20:29:57 UTC, Bastiaan Veelo wrote:
 I had some fun with `isNaN` the other day. We used it to check 
 for initialisation in an access function to cache an expensive 
 computation. This worked brilliantly until we noticed a 
 malfunction in the release version. It took a while until I 
 realised that I had given the LDC `fastmath` option to the 
 release build, which assumes NaN does not occur, which makes 
 `isNaN` misbehave.
Is there a simple example of this behavior?
Yes: ```d import std; void main() { assert(isNaN(double.nan)); } ``` Compile with LDC and options `--ffast-math -O`. -- Bastiaan.
Aug 25 2022
next sibling parent reply max haughton <maxhaton gmail.com> writes:
On Thursday, 25 August 2022 at 18:05:36 UTC, Bastiaan Veelo wrote:
 On Monday, 22 August 2022 at 22:11:23 UTC, jmh530 wrote:
 On Monday, 22 August 2022 at 20:29:57 UTC, Bastiaan Veelo 
 wrote:
 I had some fun with `isNaN` the other day. We used it to 
 check for initialisation in an access function to cache an 
 expensive computation. This worked brilliantly until we 
 noticed a malfunction in the release version. It took a while 
 until I realised that I had given the LDC `fastmath` option 
 to the release build, which assumes NaN does not occur, which 
 makes `isNaN` misbehave.
Is there a simple example of this behavior?
Yes: ```d import std; void main() { assert(isNaN(double.nan)); } ``` Compile with LDC and options `--ffast-math -O`. -- Bastiaan.
One of the nice things about UDAs and so on is that you can use them to opt into specific optimizations LLVM can do without opting into the blatantly dangerous ones. http://johanengelen.github.io/ldc/2016/10/11/Math-performance-LDC.html
Aug 25 2022
parent Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Thursday, 25 August 2022 at 18:11:11 UTC, max haughton wrote:
 One of the nice things about UDAs and so on is that you can use 
 them to opt into specific optimizations LLVM can do without 
 opting into the blatantly dangerous ones.

 http://johanengelen.github.io/ldc/2016/10/11/Math-performance-LDC.html
Yes, that is the only responsible way to use this power. The individual flags are these: https://llvm.org/docs/LangRef.html#fast-math-flags to be used with this UDA: https://wiki.dlang.org/LDC-specific_language_changes#.40.28ldc.attributes.llvmFastMathFlag.28.22flag.22.29.29. Examples can be seen in Mir: http://mir-core.libmir.org/mir_math_common.html — Bastiaan.
Aug 25 2022
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/25/22 11:05, Bastiaan Veelo wrote:
 On Monday, 22 August 2022 at 22:11:23 UTC, jmh530 wrote:
 On Monday, 22 August 2022 at 20:29:57 UTC, Bastiaan Veelo wrote:
 I had some fun with `isNaN` the other day. We used it to check for 
 initialisation in an access function to cache an expensive 
 computation. This worked brilliantly until we noticed a malfunction 
 in the release version. It took a while until I realised that I had 
 given the LDC `fastmath` option to the release build, which assumes 
 NaN does not occur, which makes `isNaN` misbehave.
Is there a simple example of this behavior?
Yes: ```d import std; void main() {     assert(isNaN(double.nan)); } ``` Compile with LDC and options `--ffast-math -O`. -- Bastiaan.
I found documentation on --fast-math here: https://clang.llvm.org/docs/UsersManual.html It includes "compiler make[s] [...] assumptions [...] Operands to floating-point operations are not equal to NaN and Inf" This is contrary to Walter's understanding, which I understand as "operations on NaN stay NaN". LLVM (at least Clang) seems to have a different take on NaN. And here is Phobos' isNaN implementation in math/traits.d: bool isNaN(X)(X x) nogc trusted pure nothrow if (isFloatingPoint!(X)) { version (all) { return x != x; } else { /* Code kept for historical context. At least on Intel, the simple test x != x uses one dedicated instruction (ucomiss/ucomisd) that runs in one cycle. Code for 80- and 128-bits is larger but still smaller than the integrals-based solutions below. Future revisions may enable the code below conditionally depending on hardware. */ // ... Removed by Ali } } LLVM must be thinking x != x is not a valid operation on NaN. Could we use a bit pattern check instead? Or write it as an asm block? Ali
Aug 25 2022
parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 25 August 2022 at 19:21:08 UTC, Ali Çehreli wrote:
 I found documentation on --fast-math here:

   https://clang.llvm.org/docs/UsersManual.html

 It includes "compiler make[s] [...] assumptions [...] Operands 
 to floating-point operations are not equal to NaN and Inf"

 This is contrary to Walter's understanding, which I understand 
 as "operations on NaN stay NaN". LLVM (at least Clang) seems to 
 have a different take on NaN.
It is not just "contrary to Walter's understanding", it is contrary to the IEEE 754 standard. Here is an article that goes into more detail about it: https://simonbyrne.github.io/notes/fastmath/
 LLVM must be thinking x != x is not a valid operation on NaN. 
 Could we use a bit pattern check instead? Or write it as an asm 
 block?
LLVM with fast-math assumes that all floating-point operands are finite, which means that it can optimize `x != x` to `false` at compile time. A sufficiently smart optimizer could in principle perform the same optimization on a bit pattern check, if it recognized the bit pattern for NaN.
Aug 25 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/25/2022 11:05 AM, Bastiaan Veelo wrote:
 Compile with LDC and options `--ffast-math -O`.
https://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-actually-do I'd stay away from fast-math. If you want to use it, however, you're on your own as D assumes IEEE math.
Aug 28 2022
parent reply Guillaume Piolat <first.last spam.org> writes:
On Sunday, 28 August 2022 at 18:31:37 UTC, Walter Bright wrote:
 On 8/25/2022 11:05 AM, Bastiaan Veelo wrote:
 Compile with LDC and options `--ffast-math -O`.
https://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-actually-do I'd stay away from fast-math. If you want to use it, however, you're on your own as D assumes IEEE math.
+1 "fast math" it also different from compiler to compiler, and sometimes makes things slower! Do you even need it for performance? Not sure, as just working on your vectorization, be it automatic or explicit, will leads to way better results. At least, that's my experience using the LLVM backend.
Aug 30 2022
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 30/08/2022 10:23 PM, Guillaume Piolat wrote:
 Do you even need it for performance? Not sure, as just working on your 
 vectorization, be it automatic or explicit, will leads to way better 
 results. At least, that's my experience using the LLVM backend.
I've talked about this quite a bit with Bruce. Our conclusion has been that explicit vectorization is usually the wrong path to take. It eats up developer time and provides very little benefit in majority of cases. If you feel like you need to reach for it, you probably haven't communicated to the backend enough information _to vectorize_. One bit of information that both LLVM and GCC can take advantage of ``assert(arg1 !is arg2);`` such a simple assert! Yet very valuable aliasing information in it. I love asserts.
Aug 30 2022
parent Guillaume Piolat <first.last spam.org> writes:
On Tuesday, 30 August 2022 at 16:01:24 UTC, rikki cattermole 
wrote:
 I've talked about this quite a bit with Bruce.

 Our conclusion has been that explicit vectorization is usually 
 the wrong path to take. It eats up developer time and provides 
 very little benefit in majority of cases.
Well I wasn't talking about manual vectorization vs autovectorization, but about fastMath. That is another debate, and I'm of a different opinion, FWIW.
Aug 30 2022
prev sibling next sibling parent reply Dom Disc <dominikus scherkl.de> writes:
On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:
 If there was a NaN value for int, I would have used it as the 
 default. int.min is not really a NaN.
But it should be! int.min is a notorious bogus value. You can't even use abs() on it: it will either give you a different type or return garbage. There is not even a working literal for it (at least for long.min). So it should never have been a valid value from beginning. The first thing I include in every of my programs is a module that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.
Aug 20 2022
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Saturday, 20 August 2022 at 18:05:59 UTC, Dom Disc wrote:
 On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright 
 wrote:
 If there was a NaN value for int, I would have used it as the 
 default. int.min is not really a NaN.
But it should be! int.min is a notorious bogus value. You can't even use abs() on it: it will either give you a different type or return garbage. There is not even a working literal for it (at least for long.min). So it should never have been a valid value from beginning. The first thing I include in every of my programs is a module that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.
By the way, you don't have to write this yourself; you can use Checked!(int, WithNaN) [1] from std.checkedint. [1] https://phobos.dpldocs.info/std.checkedint.WithNaN.html
Aug 20 2022
next sibling parent reply mw <mingwu gmail.com> writes:
 By the way, you don't have to write this yourself; you can use 
 Checked!(int, WithNaN) [1] from std.checkedint.

 [1] https://phobos.dpldocs.info/std.checkedint.WithNaN.html
BTW, where to report Dlang website (doc) bug? https://dlang.org/phobos/std_experimental_checkedint.html This module is now deprecated, use std.experimental instead. <== should be std.checkedint The link is also wrong: https://dlang.org/phobos/std_experimental.html Oh No! Page Not Found
Aug 20 2022
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
issues.dlang.org

For spec dlang.org otherwise for phobos/druntime their respective 
categories.
Aug 20 2022
prev sibling parent Paul Backus <snarwin gmail.com> writes:
On Saturday, 20 August 2022 at 21:38:13 UTC, mw wrote:
 BTW, where to report Dlang website (doc) bug?

 https://dlang.org/phobos/std_experimental_checkedint.html

 This module is now deprecated, use std.experimental instead.  
 <== should be std.checkedint

 The link is also wrong:

 https://dlang.org/phobos/std_experimental.html

 Oh No! Page Not Found
Report it on issues.dlang.org as a bug in dlang.org.
Aug 20 2022
prev sibling parent Dom Disc <dominikus scherkl.de> writes:
On Saturday, 20 August 2022 at 18:47:29 UTC, Paul Backus wrote:
 On Saturday, 20 August 2022 at 18:05:59 UTC, Dom Disc wrote:
 The first thing I include in every of my programs is a module 
 that define exactly that: an alias to byte/short/int/long that 
 takes T.min as invalid value (and uses it as default value) 
 and gives T.min+1 as its real min value.
By the way, you don't have to write this yourself; you can use Checked!(int, WithNaN) [1] from std.checkedint. [1] https://phobos.dpldocs.info/std.checkedint.WithNaN.html
I know. I like my implementation better, but that's not the point. My point is: I include this in EVERY of my programs and never use other signed integers (unsigned values I use for bit-manipulation, not for calculations). checkedint should simply BE the int type, not a module.
Aug 20 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/20/2022 11:05 AM, Dom Disc wrote:
 On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:
 If there was a NaN value for int, I would have used it as the default. int.min 
 is not really a NaN.
But it should be! int.min is a notorious bogus value. You can't even use abs() on it: it will either give you a different type or return garbage. There is not even a working literal for it (at least for long.min). So it should never have been a valid value from beginning. The first thing I include in every of my programs is a module that define exactly that: an alias to byte/short/int/long that takes T.min as invalid value (and uses it as default value) and gives T.min+1 as its real min value.
As soon as an operation is done on it, it isn't int.min anymore. It has some characteristics of a NaN, but not enough.
Aug 20 2022
parent reply Dom Disc <dominikus scherkl.de> writes:
On Sunday, 21 August 2022 at 03:46:13 UTC, Walter Bright wrote:
 On 8/20/2022 11:05 AM, Dom Disc wrote:
 that define exactly that: an alias to byte/short/int/long 
 that takes T.min as invalid value (and uses it as default 
 value) and gives T.min+1 as its real min value.
As soon as an operation is done on it, it isn't int.min anymore. It has some characteristics of a NaN, but not enough.
It's no problem to implement saveint so, that int.min stays at that value for all operations (except direct assignment). Ok, as library this may cost a little performance, but I think it's worth it.
Aug 21 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/21/2022 2:00 AM, Dom Disc wrote:
 It's no problem to implement saveint so, that int.min stays at that value for 
 all operations (except direct assignment). Ok, as library this may cost a
little 
 performance, but I think it's worth it.
This may be what you're looking for: https://dlang.org/phobos/std_checkedint.html
Aug 25 2022
prev sibling parent kdevel <kdevel vogtner.de> writes:
On Saturday, 20 August 2022 at 01:01:07 UTC, Walter Bright wrote:
 The NaN value for char is 0xFF [...]. [...] (0xFF is specified 
 as an illegal
 code point in Unicode.)
The code point OxFF = U+00FF is ÿ: <https://codepoints.net/U+00FF>. It is the code unit [1]: "In valid UTF-8, the bytes 0xF5..0xFF cannot occur." [1] https://stackoverflow.com/questions/1319022/really-good-bad-utf-8-example-test-data
Aug 20 2022
prev sibling parent reply claptrap <clap trap.com> writes:
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!
Aug 19 2022
parent zjh <fqbqrr 163.com> writes:
On Friday, 19 August 2022 at 23:11:35 UTC, claptrap wrote:

 double w; // compiler says NO!
The compiler should prohibit such `statements`.
Aug 19 2022
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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.
Aug 19 2022
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/19/22 8:49 PM, Walter Bright wrote:
 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.
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
Aug 19 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/19/2022 8:15 PM, Steven Schveighoffer wrote:
 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.
The difference is it must be intentionally set for a field's value, and it is only for that field's value. It is not the default.
Aug 25 2022
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Friday, 19 August 2022 at 17:14:35 UTC, Steven Schveighoffer 
wrote:
 ```c
 ReallyLargeStruct foo = { 0 };
 ```

 There just is no equivalent in D. In order to set all fields to 
 0, I would have to specify a complete layout of the entire 
 thing. This could probably be done via introspection. But I 
 just don't like it even in that case.
Maybe something like this: ```d template ZeroInit(T) { union U { byte[T.sizeof] a; T zeroed; } enum ZeroInit = U().zeroed; } struct S { float f; float[2] a; } void main() { S s = ZeroInit!S; assert(s.f == 0); assert(s.a == [0,0]); } ```
Aug 20 2022
prev sibling next sibling parent reply Hipreme <msnmancini hotmail.com> writes:
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:
 As someone coming from Java to use D, I find it myself quite 
 annoying that float and double are initialized to `nan`.

 This is really bad, it is hard to detect for newcomers, there 
 is no flag by default to throw an exception when some 
 operation on nan is done. It can be misleading if you're not 
 paying a lot of attention to what you're doing.

 What I suggest is what any sane people would: use 0 as the 
 start for float and double. 0 is the most common sense as a 
 starting point for everything, and, there are 2 options we 
 could go:


 1: Emit a compilation error that every variable must be 
 initialized (I thought D were trying to avoid runtime errors)
 2: 0 init all types, so, none is actually invalid before use


 Even `char` took me as surprise to know it actually starts as 
 0xff, I lost a bit of time trying to find that bug because it 
 is so common that variables init as zero.

 Although the `char` is a bit different beast in terms of 
 breaking change, I really *can't see* anyone actually 
 depending that your float is being initialized with `nan`, so 
 I really would like to know how much people agree with this 
 idea. It is so common to stumble on that problem that it is 
 starting to feel as a real mistake.
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. There's a lot of developers which uses bool and int because they make sense, when dealing with floating point they forget about that they do not make sense. I've never had any problem with float defaulting to 0 on Java. If the error happens, I get at max division by 0 exception. NaN does not cause this exception which actually makes the bug harder to find.
Aug 19 2022
next sibling parent Basile B. <b2.temp gmx.com> writes:
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.
Aug 19 2022
prev sibling parent Max Samukha <maxsamukha gmail.com> writes:
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.
Aug 19 2022
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
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.
Aug 19 2022
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Aug 19 2022
next sibling parent reply Tejas <notrealemail gmail.com> writes:
On Saturday, 20 August 2022 at 04:04:08 UTC, Ali Çehreli wrote:
 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
`units of measure` https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure
Aug 20 2022
parent Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 20 August 2022 at 07:08:50 UTC, Tejas wrote:

 `units of measure`

 https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure
If needed, units are possible at compile time using template and enumerator. Walter showed much better in DConf'22: **Title:** Using Enums to Generate Scoped List of Names, p.32 **Source:** https://github.com/dlang/dconf.org/blob/master/2022/slides/bright.pdf Thanks to Andrey Zherikov SDB 79
Aug 20 2022
prev sibling next sibling parent reply Max Samukha <maxsamukha gmail.com> writes:
On Saturday, 20 August 2022 at 04:04:08 UTC, Ali Çehreli wrote:
 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.
Arrays are outliars as well because .init is not an "invalid" value of them. string s; string s2 = s ~ "foo"; // omg, s2 now is a valid string! And any aggregation of the outliars is also an outlier. And now there are too many of them to be called outliars.
Aug 20 2022
parent Max Samukha <maxsamukha gmail.com> writes:
On Saturday, 20 August 2022 at 09:53:58 UTC, Max Samukha wrote:

 Arrays are outliars as well because .init is not an "invalid" 
 value of them.

 string s;
 string s2 = s ~ "foo"; // omg, s2 now is a valid string!

 And any aggregation of the outliars is also an outlier. And now 
 there are too many of them to be called outliars.
*outlier I don't know why my brain did it to me.
Aug 20 2022
prev sibling parent reply Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Saturday, 20 August 2022 at 04:04:08 UTC, Ali Çehreli wrote:
 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
Enter `std.typecons.Typefef`: ```d import std; alias Distance = Typedef!(double, 0.0, "distance"); alias Temperature = Typedef!(double, 0.0, "temperature"); void main() { Temperature t; Distance d; d += 4.5; // t = d; // does not compile } ``` However, type information can get lost in intermediate results: ```d t = 0.5 + d; // result is double ``` — Bastiaan
Aug 20 2022
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/20/22 14:07, Bastiaan Veelo wrote:

 alias Distance = Typedef!(double, 0.0, "distance");
Great! :)
 However, type information can get lost in intermediate results:
 ```d
      t = 0.5 + d; // result is double
 ```
Yeah, that's a bummer. Perhaps something like this could work: "have all the functionality of a double but don't implicitly convert to one." (Ironically, alias this is the implicit conversion tool.) And what do I mean? Only when being passed to a function? I don't know... :/ Ali
Aug 20 2022
prev sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 20 August 2022 at 21:07:33 UTC, Bastiaan Veelo wrote:
 ```d
 import std;

 alias Distance = Typedef!(double, 0.0, "distance");
 alias Temperature = Typedef!(double, 0.0, "temperature");

 void main()
 {
     Temperature t;
     Distance d;
     d += 4.5;
     // t = d; // does not compile
 }
 ```
 However, type information can get lost in intermediate results:
 ```d
     t = 0.5 + d; // result is double
 ```
It's very simple and beautiful. Thank you, very delicious! SDB 79
Aug 21 2022
parent novice2 <sorry noem.ail> writes:
On Monday, 22 August 2022 at 01:09:53 UTC, Salih Dincer wrote:
 It's very simple and beautiful. Thank you, very delicious!
except for ugly error messages :(
Aug 21 2022
prev sibling next sibling parent reply Dukc <ajieskola gmail.com> writes:
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:
 Although the `char` is a bit different beast in terms of 
 breaking change, I really *can't see* anyone actually depending 
 that your float is being initialized with `nan`, so I really 
 would like to know how much people agree with this idea. It is 
 so common to stumble on that problem that it is starting to 
 feel as a real mistake.
I personally like how D does it. Once you know that floats have a "nothing" value, it's very convenient that it's the initialisation value, for the same reason `null` is a convenient initialisation value for pointers and class references. But I can see that if I didn't know about NaNs, this would be annoying. The probably many other languages) do so one is easily surprised. However, the big philosophy behind it is that D *always* uses an "empty" value as the initialisation value if there is one, so for D this is the right thing to do. Using 0 as float `.init` would be inconsistent with rest of the language. Whether this underlying philosophy is a good idea is debatable though. Personally I think the philosophy has it's ups and downs but easy to like once you get used to it.
Aug 20 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/20/2022 3:17 PM, Dukc wrote:

 probably many other languages) do so one is easily surprised.
C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.
Aug 22 2022
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/22/22 8:50 PM, Walter Bright wrote:
 On 8/20/2022 3:17 PM, Dukc wrote:

 do so one is easily surprised.
C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.
Agreed that C/C++ initializing with garbage is the worst option. I'm curious what all languages do that actually use an initial value? -Steve
Aug 22 2022
next sibling parent reply jordan4ibanez <jordan4ibanez002 gmail.com> writes:
Did NaN replace any float/double values in memory?
Aug 22 2022
next sibling parent jordan4ibanez <jordan4ibanez002 gmail.com> writes:
I have seen how polar people's view points are on this issue. 
This is why I have created a library to solve this. Now people 
who wish floating points init to 0 can have it!

https://code.dlang.org/packages/j_init
Aug 23 2022
prev sibling parent reply jordan4ibanez <jordan4ibanez002 gmail.com> writes:
I have seen how polar people's view points are on this issue. 
This is why I have created a library to solve this. Now people 
who wish floating points init to 0 can have it!

https://code.dlang.org/packages/j_init
Aug 23 2022
parent bauss <jacobbauss gmail.com> writes:
On Tuesday, 23 August 2022 at 08:03:44 UTC, jordan4ibanez wrote:
 I have seen how polar people's view points are on this issue. 
 This is why I have created a library to solve this. Now people 
 who wish floating points init to 0 can have it!

 https://code.dlang.org/packages/j_init
The problem with this is metaprogramming will break because you will need to handle your Float/Double type apart from float/double. Ex. ```d // This function might not be something we can modify auto add(Number)(Number x, Number y) if (is(Number == float) || is(Number == double)) { return x + y; } void main() { Float f1; Float f2; // Error: // writeln(add(f1, f2)); // To fix it: writeln(add(cast(float)f1, f2)); } ``` By using your struct implementation then one has to handle those two types as well, otherwise it will break from stuff like shown above. So there's really no actual good way to override default initialization values.
Aug 23 2022
prev sibling next sibling parent reply IGotD- <nise nise.com> writes:
On Tuesday, 23 August 2022 at 01:19:35 UTC, Steven Schveighoffer 
wrote:
 Agreed that C/C++ initializing with garbage is the worst option.



 I'm curious what all languages do that actually use an initial 
 value?

 -Steve
C++11 default value initialization exist. Meaning this ```c++ double x{}; ``` is going to be initialized to zero. D is really an outlier here with default initialization to NaN. I would rephrase you initial question to a challenge, find a language other than D that default initializes floats to NaN.
Aug 23 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/23/22 01:07, IGotD- wrote:
 On Tuesday, 23 August 2022 at 01:19:35 UTC, Steven Schveighoffer wrote:
 Agreed that C/C++ initializing with garbage is the worst option.



 I'm curious what all languages do that actually use an initial value?

 -Steve
C++11 default value initialization exist. Meaning this ```c++ double x{}; ```
At that level, it's the same in D: // Garbage value: double x = void; // D double x; // C++ // Zero value: double x = 0; // D double x{}; // C++ However, there is a difference with members: struct S { double x; } // Add ; here for C++ S(); // S.x is double.nan in D S{}; // S.x is 0 in C++
 find a language other than D that default initializes
 floats to NaN.
I failed with a quick search. However, I still think initial value being nan is not an issue even if it does not meet programmer expectations. For example, D could not leave the value as garbage as C++ programmers comfortably expect so. And I am pretty sure the default value cannot be changed for D at this time. Ali
Aug 23 2022
parent IGotD- <nise nise.com> writes:
On Tuesday, 23 August 2022 at 15:27:05 UTC, Ali Çehreli wrote:
 However, I still think initial value being nan is not an issue 
 even if it does not meet programmer expectations. For example, 
 D could not leave the value as garbage as C++ programmers 
 comfortably expect so. And I am pretty sure the default value 
 cannot be changed for D at this time.

 Ali
It's too late for D2 but for D3 this should be taken into consideration. We are starting to acquire a big list of things that can be done for D3 now.
Aug 23 2022
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/22/2022 6:19 PM, Steven Schveighoffer wrote:
 I'm curious what all languages do that actually use an initial value?
AFAIK D is unique in using NaN.
Aug 24 2022
prev sibling next sibling parent reply claptrap <clap trap.com> writes:
On Tuesday, 23 August 2022 at 00:50:21 UTC, Walter Bright wrote:
 On 8/20/2022 3:17 PM, Dukc wrote:

 languages) do so one is easily surprised.
C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.
Dont most C/C++ compilers have warnings for initialised variables? I'm sure MSVC did when I was using it, but its 15 years ago now.
Aug 23 2022
next sibling parent Tejas <notrealemail gmail.com> writes:
On Tuesday, 23 August 2022 at 09:00:59 UTC, claptrap wrote:
 On Tuesday, 23 August 2022 at 00:50:21 UTC, Walter Bright wrote:
 On 8/20/2022 3:17 PM, Dukc wrote:

 languages) do so one is easily surprised.
C and C++ initialize them to garbage unless it is a global/static variable. That's probably the worst option, as it results in Heisenbugs that are very hard to track down.
Dont most C/C++ compilers have warnings for initialised variables? I'm sure MSVC did when I was using it, but its 15 years ago now.
Yeah, but there's also bugs in gcc, apparently https://stackoverflow.com/questions/14132898/gcc-wuninitialized-wmaybe-uninitialized-issues
Aug 23 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/23/2022 2:00 AM, claptrap wrote:
 Dont most C/C++ compilers have warnings for initialised variables? I'm sure
MSVC 
 did when I was using it, but its 15 years ago now.
I just tried it with gcc. No warning.
Aug 23 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 24 August 2022 at 05:57:38 UTC, Walter Bright wrote:
 On 8/23/2022 2:00 AM, claptrap wrote:
 Dont most C/C++ compilers have warnings for initialised 
 variables? I'm sure MSVC did when I was using it, but its 15 
 years ago now.
I just tried it with gcc. No warning.
Most of gcc's warnings, including this one, are not enabled by default. If you compile with -Wall, you will get a warning.
Aug 24 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/24/2022 5:17 AM, Paul Backus wrote:
 On Wednesday, 24 August 2022 at 05:57:38 UTC, Walter Bright wrote:
 On 8/23/2022 2:00 AM, claptrap wrote:
 Dont most C/C++ compilers have warnings for initialised variables? I'm sure 
 MSVC did when I was using it, but its 15 years ago now.
I just tried it with gcc. No warning.
Most of gcc's warnings, including this one, are not enabled by default. If you compile with -Wall, you will get a warning.
Fair enough, though that makes it clear that there are many languages called C, and Standard C does not complain about it.
Aug 24 2022
prev sibling parent reply Zoadian <no no.no> writes:
On Tuesday, 23 August 2022 at 00:50:21 UTC, Walter Bright wrote:
 C and C++ initialize them to garbage unless it is a 
 global/static variable. That's probably the worst option, as it 
 results in Heisenbugs that are very hard to track down.
I agree that NaN for uninitialized floats is the best option. However, can we get a switch to force initialization of floats? it would be of great help to quickly find the place where one forgot to initialize a variable.
Aug 23 2022
parent jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 23 August 2022 at 11:08:36 UTC, Zoadian wrote:
 On Tuesday, 23 August 2022 at 00:50:21 UTC, Walter Bright wrote:
 C and C++ initialize them to garbage unless it is a 
 global/static variable. That's probably the worst option, as 
 it results in Heisenbugs that are very hard to track down.
I agree that NaN for uninitialized floats is the best option. However, can we get a switch to force initialization of floats? it would be of great help to quickly find the place where one forgot to initialize a variable.
Walter makes good points in favor of NaN as a default, but I agree this would be useful for identifying the source of the problem, so long as it is primarily used for debugging purposes. For instance, if we could do something like `debug(force-float-initialization, VALUE)` where VALUE defaults to zero but represents the value that uninitialized floats would get initialized to, then that would be helpful (a pragma might be an alternative to a debug statement). After all, if you are writing a function that unexpectedly returns a NaN, then you can put that up top and see if it returns something else. Being able to modify the VALUE would help identify the issue in more complicated functions.
Aug 23 2022
prev sibling next sibling parent jordan4ibanez <jordan4ibanez002 gmail.com> writes:
We could make it the worst of both worlds. We could have it so 
sometimes an unitialized float or double is NaN and make it be 
the garbage data that was the memory address depending on if a 
random number is below 0.5 or not.

I'm kidding.

I would actually prefer it to throw an error if you did not 
initialize a variable. :) This would make programming more 
explicit upfront but prevent you from tearing out your hair in a 
few months where a part of a library you're using suddenly starts 
throwing weird errors out and you are left with a cup full of 
tears. This goes for all variables of primitive type to use Java 
speak. This would not only solve the issue of "OI IT SHOULD BE 
ZERO!!" and "OI IT SHOULD BE NAN!!!". No way Jose, it should be 
what you tell it to be because the computer should do what you 
told it to do when creating those values, not guess. Because it 
can only tell how you're trying to do it, not what you're trying 
to do. It's not a soothsayer, it's a glorified calculator.
Aug 20 2022
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
Consider the following pattern, which doesn't appear frequently, but frequently 
enough:

     double x;
     if (condition) {
         x = 5;
         ...
     }
     ...               // (1)
     if (condition) {
        foo(x);
     }

Imagine there's a lot more code omitted which obscures the pattern. This code
is 
correct.

Now, maintainer adds `bar(x)` at (1).

The scenarios:

1. x is default initialized to NaN. bar(x) produces a NaN result on everything 
dependent on x. User knows there's a problem.

2. x is default initialized to 0. bar(0) may exhibit problems, but these 
problems won't necessarily be noticed.

3. compiler complains that `double x;` needs an initializer. To shut up the 
compiler, the user initializes it to 0, without putting much thought into it. 
bar(0) may exhibit problems, but these won't necessarily be noticed.

4. compiler complains that `double x;` needs an initializer. Coder just
schlepps 
in a 0. Yes, this happens. Maintainer wastes time wondering why x is
initialized 
to 0, as that may be a nonsense value for x. Maintainer wonders if this unused 
initialization has a purpose, maybe it is the result of a bad refactoring? 
Wastes more time investigating it.

D chose option 1.

BTW, option 1 is very analogous to the common "Optional" types which can be 
either an error value or a valid value. Optional types propagate just like NaNs
do.
Aug 21 2022
next sibling parent reply claptrap <clap trap.com> writes:
On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:
 Consider the following pattern, which doesn't appear


 1. x is default initialized to NaN. bar(x) produces a NaN 
 result on everything dependent on x. User knows there's a 
 problem.

 2. x is default initialized to 0. bar(0) may exhibit problems, 
 but these problems won't necessarily be noticed.
This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.
Aug 21 2022
parent reply drug007 <drug2004 bk.ru> writes:
On 8/21/22 20:28, claptrap wrote:
 On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:
 Consider the following pattern, which doesn't appear


 1. x is default initialized to NaN. bar(x) produces a NaN result on 
 everything dependent on x. User knows there's a problem.

 2. x is default initialized to 0. bar(0) may exhibit problems, but 
 these problems won't necessarily be noticed.
This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.
It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong? To detect it you should track down manually checking the intermediate results that is manually calculate results and compare to what you get. It takes much more time than checking if the value is NaN.
Aug 21 2022
next sibling parent reply apz28 <home home.com> writes:
On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:
 On 8/21/22 20:28, claptrap wrote:
 On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:
 Consider the following pattern, which doesn't appear


 1. x is default initialized to NaN. bar(x) produces a NaN 
 result on everything dependent on x. User knows there's a 
 problem.

 2. x is default initialized to 0. bar(0) may exhibit 
 problems, but these problems won't necessarily be noticed.
This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.
It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong? To detect it you should track down manually checking the intermediate results that is manually calculate results and compare to what you get. It takes much more time than checking if the value is NaN.
Price for this float=NaN & char=FF 1. Runtime bloat -> all struct/class with (float or char) need special initializer 2. Slow -> all struct/class not able to utilize zero initialized from memory manager 3. Inconsistent with other value types (all zero bits) 4. Aggregated/Sum float var should start with zero So -> Better error when var is not initialized than this special value
Aug 21 2022
next sibling parent IGotD- <nise nise.com> writes:
On Sunday, 21 August 2022 at 19:57:52 UTC, apz28 wrote:
 Price for this float=NaN & char=FF
 1. Runtime bloat -> all struct/class with (float or char) need 
 special initializer
 2. Slow -> all struct/class not able to utilize zero 
 initialized from memory manager
 3. Inconsistent with other value types (all zero bits)
 4. Aggregated/Sum float var should start with zero

 So -> Better error when var is not initialized than this 
 special value
These are very good points which I agree with. Previously I was a bit it didn't matter for me (either Nan or 0.0) but with these my mind tipped over in favor of zero for both char and floats. It is a better design because of the consistency as well it enables the optimizer to use large moves in order to initialize the memory. However, will it be the real use case after optimizing away unused values, that is the question.
Aug 21 2022
prev sibling next sibling parent drug007 <drug2004 bk.ru> writes:
On 8/21/22 22:57, apz28 wrote:
 It will be noticed but what price? You've initialized all vars to 0 so 
 how do you know that this exactly initialization to zero is wrong? To 
 detect it you should track down manually checking the intermediate 
 results that is manually calculate results and compare to what you 
 get. It takes much more time than checking if the value is NaN.
Price for this float=NaN & char=FF 1. Runtime bloat -> all struct/class with (float or char) need special initializer 2. Slow -> all struct/class not able to utilize zero initialized from memory manager 3. Inconsistent with other value types (all zero bits) 4. Aggregated/Sum float var should start with zero So -> Better error when var is not initialized than this special value
Let me disagree to you 1) Every struct/class needs special initializer because datatypes definitely are different. According to your logic user should initialize all fields to zero and only zero. No other values are possible. It is really strange point. 2) Again you argue against non-zero initialized fields in aggregate types. 3) Once again - not all types should be zero initialized. For example, covariance matrix in Kalman Filter should NOT be initialized to zero. In other case the filter won't work at all. 4) No, you are wrong again. sum accumulator should not start with zero, in other case sum algorithm has no this argument at all, right?
Aug 21 2022
prev sibling parent Dom Disc <dominikus scherkl.de> writes:
On Sunday, 21 August 2022 at 19:57:52 UTC, apz28 wrote:
 Price for this float=NaN & char=FF
 1. Runtime bloat -> all struct/class with (float or char) need 
 special initializer
No. If intentional you can explicitly leave them uninitialized (= void)
 2. Slow -> all struct/class not able to utilize zero 
 initialized from memory manager
Fill with specific pattern is _really_ fast, so very very low performance lost - and only once as you shouldn't do initialization in a loop, do you?
 3. Inconsistent with other value types (all zero bits)
I agree to this, but you choose the wrong solution. Correct would be to initialize the remaining types also with an invalid value instead of zero.
 4. Aggregated/Sum float var should start with zero
Why? For this to be an argument on its own, it should not refer to (1)..(3) So: no argument left. Too bad.
Aug 22 2022
prev sibling parent reply claptrap <clap trap.com> writes:
On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:
 On 8/21/22 20:28, claptrap wrote:
 On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:
 Consider the following pattern, which doesn't appear


 1. x is default initialized to NaN. bar(x) produces a NaN 
 result on everything dependent on x. User knows there's a 
 problem.

 2. x is default initialized to 0. bar(0) may exhibit 
 problems, but these problems won't necessarily be noticed.
This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.
It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong?
You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised. You're just inventing nonsense scenarios. And seriously if you're looking a variable and dont know what value it should be initialised too you literally *dont know what your doing*.
 To detect it you should track down manually checking the 
 intermediate results that is manually calculate results and 
 compare to what you get. It takes much more time than checking 
 if the value is NaN.
Occasionally you might have to do a bit of mental arithmetic, but not often, I'm seriously wondering why you think it's so hard?
Aug 22 2022
next sibling parent reply drug007 <drug2004 bk.ru> writes:
On 8/22/22 18:04, claptrap wrote:
 On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:
 On 8/21/22 20:28, claptrap wrote:
 On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:
 Consider the following pattern, which doesn't appear


 1. x is default initialized to NaN. bar(x) produces a NaN result on 
 everything dependent on x. User knows there's a problem.

 2. x is default initialized to 0. bar(0) may exhibit problems, but 
 these problems won't necessarily be noticed.
This is the problem, you suggest that if a variable is zero initialised in error the problems it causes "wont necessarily" be noticed. I'm saying that's not true, I'm saying it will almost always be noticed.
It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong?
You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised. You're just inventing nonsense scenarios.
But that is my point - not all variables initialize to zero. It is my statement that this is nonsense scenarios. Reread the post carefully.
 
 And seriously if you're looking a variable and dont know what value it 
 should be initialised too you literally *dont know what your doing*.
 
 
 To detect it you should track down manually checking the intermediate 
 results that is manually calculate results and compare to what you 
 get. It takes much more time than checking if the value is NaN.
Occasionally you might have to do a bit of mental arithmetic, but not often, I'm seriously wondering why you think it's so hard?
Just because I've done math calculations before? And no, I didn't mean mental arithmetic. I meant numerical matrix operations from inputs to outputs just to track down where was wrong zero initialization. In some cases zero initialization is invalid, for example covariance of random variables. But NaN is invalid always. That is its advantage.
Aug 22 2022
parent reply claptrap <clap trap.com> writes:
On Monday, 22 August 2022 at 15:56:16 UTC, drug007 wrote:
 On 8/22/22 18:04, claptrap wrote:
 On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:
 On 8/21/22 20:28, claptrap wrote:
 On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright
It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong?
You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised. You're just inventing nonsense scenarios.
But that is my point - not all variables initialize to zero. It is my statement that this is nonsense scenarios. Reread the post carefully.
"You've initialized all vars to 0" I can only respond to what you write, (which was a nonsense scenario.)
 Occasionally you might have to do a bit of mental arithmetic, 
 but not often, I'm seriously wondering why you think it's so 
 hard?
 
Just because I've done math calculations before? And no, I didn't mean mental arithmetic. I meant numerical matrix operations from inputs to outputs just to track down where was wrong zero initialization. In some cases zero initialization is invalid, for example covariance of random variables. But NaN is invalid always. That is its advantage.
I've been programming for over 30 years, mostly DSP and some numerical stuff, statistical analysis. My experience is that its not a big deal. My point is people are massively overselling how much of a problem bad inits are to track down.
Aug 22 2022
parent drug007 <drug2004 bk.ru> writes:
On 8/23/22 02:08, claptrap wrote:
 On Monday, 22 August 2022 at 15:56:16 UTC, drug007 wrote:
 On 8/22/22 18:04, claptrap wrote:
 On Sunday, 21 August 2022 at 17:56:58 UTC, drug007 wrote:
 On 8/21/22 20:28, claptrap wrote:
 On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright
It will be noticed but what price? You've initialized all vars to 0 so how do you know that this exactly initialization to zero is wrong?
You dont initialise all variables to zero, Ive just looked at some om my code and in 4000 lines i found two default init ints and maybe 50+ explicitly initialised. You're just inventing nonsense scenarios.
But that is my point - not all variables initialize to zero. It is my statement that this is nonsense scenarios. Reread the post carefully.
"You've initialized all vars to 0" I can only respond to what you write, (which was a nonsense scenario.)
I'm so sorry, but you failed to reread post above carefully again. My point is not all data initialize zero. That is the reason why floating point number should be defaulted as NaN. Because you clearly can see what data hasn't been initialized at all.
 
 Occasionally you might have to do a bit of mental arithmetic, but not 
 often, I'm seriously wondering why you think it's so hard?
Just because I've done math calculations before? And no, I didn't mean mental arithmetic. I meant numerical matrix operations from inputs to outputs just to track down where was wrong zero initialization. In some cases zero initialization is invalid, for example covariance of random variables. But NaN is invalid always. That is its advantage.
I've been programming for over 30 years, mostly DSP and some numerical stuff, statistical analysis. My experience is that its not a big deal.
My experience is it is a big deal enough.
 My point is people are massively overselling how much of a problem bad 
 inits are to track down.
Aug 22 2022
prev sibling parent reply Dom Disc <dominikus scherkl.de> writes:
On Monday, 22 August 2022 at 15:04:25 UTC, claptrap wrote:

 You dont initialise all variables to zero, Ive just looked at 
 some om my code and in 4000 lines i found two default init ints 
 and maybe 50+ explicitly initialised.
So, if you rarely ever use default initialization, why do you care to which value it might be initialized? For the analysis which default value is the better one, only the cases where it is used matters. You need only count how often is a variable not initialized, and of those how many times is this (a) a bug or (b) intended. Now imagine you review code from someone else (e.g. at an assessment). In this case you have to carefully check every case of uninitialized variable. If the code always explicitly say =void or =0, there are no such cases, so you might save a LOT of time. So better get used to ALWAYS initialize explicitly and consider EVERY occurrence of uninitialized variable to be a bug. And bogus code should NEVER result in a value that could also occur as a valid result, so the compiler should help as much as it can by using an invalid value if one is available.
Aug 22 2022
parent claptrap <clap trap.com> writes:
On Monday, 22 August 2022 at 19:49:02 UTC, Dom Disc wrote:
 On Monday, 22 August 2022 at 15:04:25 UTC, claptrap wrote:

 You dont initialise all variables to zero, Ive just looked at 
 some om my code and in 4000 lines i found two default init 
 ints and maybe 50+ explicitly initialised.
So, if you rarely ever use default initialization, why do you care to which value it might be initialized?
NaN or Zero I dont really care, I just got sucked in, there's a fair amount of BS floating around.
Aug 22 2022
prev sibling next sibling parent zjh <fqbqrr 163.com> writes:
On Sunday, 21 August 2022 at 16:51:51 UTC, Walter Bright wrote:

 3. compiler complains that `double x;` needs an initializer. To 
 shut up the compiler, the user initializes it to 0, without 
 putting much thought into it. bar(0) may exhibit problems, but 
 these won't necessarily be noticed.
In many cases, `0` can solve that problem. The real problem is that sometimes it is not appropriate to initialize with 0. The compiler should collect these 0 initialization locations to better track possible `mistakes`.
Aug 21 2022
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/21/22 12:51 PM, Walter Bright wrote:
 Consider the following pattern, which doesn't appear frequently, but 
 frequently enough:
 
      double x;
      if (condition) {
          x = 5;
          ...
      }
      ...               // (1)
      if (condition) {
         foo(x);
      }
 
 Imagine there's a lot more code omitted which obscures the pattern. This 
 code is correct.
 
 Now, maintainer adds `bar(x)` at (1).
 
 The scenarios:
 
 1. x is default initialized to NaN. bar(x) produces a NaN result on 
 everything dependent on x. User knows there's a problem.
How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?
 2. x is default initialized to 0. bar(0) may exhibit problems, but these 
 problems won't necessarily be noticed.
Just like NaN.
 3. compiler complains that `double x;` needs an initializer. To shut up 
 the compiler, the user initializes it to 0, without putting much thought 
 into it. bar(0) may exhibit problems, but these won't necessarily be 
 noticed.
 
 4. compiler complains that `double x;` needs an initializer. Coder just 
 schlepps in a 0. Yes, this happens. Maintainer wastes time wondering why 
 x is initialized to 0, as that may be a nonsense value for x. Maintainer 
 wonders if this unused initialization has a purpose, maybe it is the 
 result of a bad refactoring? Wastes more time investigating it.
Huh? Why are there 2 identical situations here? I'll also point out that not initializing an integer is sometimes intentionally done (because it's equivalent to initializing to 0). If I see someone didn't assign a value to an int, I don't question if it was an accident, I expect that they meant it. Also, you forgot: 5. Maintainer expected x to default to 0 (because that's what most types do), and expected bar to be called with 0 or 5. Now, since bar saved the result of it's calculation elsewhere, and then far away from this code, the result is used in some computation that finally makes its way to output in some fashion (and possibly not a specific printing of the value), now there's a puzzle to solve, and no way to know it can be traced back to x without hours/days of searching.
 D chose option 1.
And there's probably no way that it changes. But in my mind the correct answer is to intialize to 0. -Steve
Aug 22 2022
next sibling parent reply wjoe <invalid example.com> writes:
On Monday, 22 August 2022 at 11:41:33 UTC, Steven Schveighoffer 
wrote:
 On 8/21/22 12:51 PM, Walter Bright wrote:
 Consider the following pattern, which doesn't appear 
 frequently, but frequently enough:
 
      double x;
      if (condition) {
          x = 5;
          ...
      }
      ...               // (1)
      if (condition) {
         foo(x);
      }
 
 Imagine there's a lot more code omitted which obscures the 
 pattern. This code is correct.
 
 Now, maintainer adds `bar(x)` at (1).
 
 The scenarios:
 
 1. x is default initialized to NaN. bar(x) produces a NaN 
 result on everything dependent on x. User knows there's a 
 problem.
How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?
Assuming this isn't a rhetoric question... It's not as convenient as a segfault but at some point, the error becomes obvious. I would start there to inspect variables, identify the NaNs. Then I would trace them in a debugger and go up the call chain until I find the location where it became NaN. Then I would identify the source which introduced the NaN and trace that back until I found its origin. The advantage I see in NaN is that it's always (instead of only almost always) immediately obvious that it's wrong whereas 0.0 can be valid or invalid so you need to figure out which one it is which requires an extra step.
Aug 22 2022
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/22/22 9:17 AM, wjoe wrote:
 On Monday, 22 August 2022 at 11:41:33 UTC, Steven Schveighoffer wrote:
 On 8/21/22 12:51 PM, Walter Bright wrote:
 Consider the following pattern, which doesn't appear frequently, but 
 frequently enough:

      double x;
      if (condition) {
          x = 5;
          ...
      }
      ...               // (1)
      if (condition) {
         foo(x);
      }

 Imagine there's a lot more code omitted which obscures the pattern. 
 This code is correct.

 Now, maintainer adds `bar(x)` at (1).

 The scenarios:

 1. x is default initialized to NaN. bar(x) produces a NaN result on 
 everything dependent on x. User knows there's a problem.
How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?
Assuming this isn't a rhetoric question...
It's not.
 It's not as convenient as a segfault but at some point, the error 
 becomes obvious.
Does it? And "at some point" it becomes obvious no matter what the error you made.
 I would start there to inspect variables, identify the 
 NaNs.
What if you can't? What if it only happens randomly, and you don't just happen to have a debugger attached? I'm not saying it's easier with 0, but just not any different.
 Then I would trace them in a debugger and go up the call chain until I 
 find the location where it became NaN. Then I would identify the source 
 which introduced the NaN and trace that back until I found its origin.
If you have a chance to use a debugger and it happens at that time.
 
 The advantage I see in NaN is that it's always (instead of only almost 
 always) immediately obvious that it's wrong whereas 0.0 can be valid or 
 invalid so you need to figure out which one it is which requires an 
 extra step.
 
It might be noticed that it's NaN. It also might not. It depends on how it's used. Either way, you need to find the source, and NaN doesn't help unless you want to start either instrumenting *all* code (possibly including code you don't control), or use a debugger (which isn't always possible). Can we have some kind of linting system that identifies NaNs that are used? -Steve
Aug 22 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/22/2022 7:06 AM, Steven Schveighoffer wrote:
 It's not as convenient as a segfault but at some point, the error becomes 
 obvious.
Does it? And "at some point" it becomes obvious no matter what the error you made.
The point is, since 0.0 is a common value for a floating point value to be, just when does it become obvious that it is wrong? Are you really going to notice if your computation is 5% off? Isn't it a *lot* more obvious that it is wrong if it is NaN?
 I would start there to inspect variables, identify the NaNs.
What if you can't? What if it only happens randomly, and you don't just happen to have a debugger attached? I'm not saying it's easier with 0, but just not any different.
0.0 is hardly a rare value, even in correct calculations. NaN is always wrong.
 Then I would trace them in a debugger and go up the call chain until I find 
 the location where it became NaN. Then I would identify the source which 
 introduced the NaN and trace that back until I found its origin.
If you have a chance to use a debugger and it happens at that time.
0 initialization wouldn't make it better.
 The advantage I see in NaN is that it's always (instead of only almost always) 
 immediately obvious that it's wrong whereas 0.0 can be valid or invalid so you 
 need to figure out which one it is which requires an extra step.
It might be noticed that it's NaN. It also might not. It depends on how it's used.
NaN propagates. 0.0 does not.
 Either way, you need to find the source, and NaN doesn't help unless you want
to 
 start either instrumenting *all* code (possibly including code you don't 
 control), or use a debugger (which isn't always possible).
Such a situation is objectively worse with 0.0. Is instrumenting all the code to detect 0.0 going to work? Nope, too many false positives, as 0.0 is a common value for floating point numbers.
 Can we have some kind of linting system that identifies NaNs that are used?
I have no objection to a linter that flags default initializations of floating point values. It shouldn't be part of the D compiler, though.
Aug 22 2022
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/22/22 8:46 PM, Walter Bright wrote:
 On 8/22/2022 7:06 AM, Steven Schveighoffer wrote:
 It's not as convenient as a segfault but at some point, the error 
 becomes obvious.
Does it? And "at some point" it becomes obvious no matter what the error you made.
The point is, since 0.0 is a common value for a floating point value to be, just when does it become obvious that it is wrong? Are you really going to notice if your computation is 5% off? Isn't it a *lot* more obvious that it is wrong if it is NaN?
This is a highly dependent situation. It could be 0, which is 100% off. It could be 5%. It could be 0.0001% off, which might actually not be a problem that is noticed. So I have an actual true story. One of the calculation spreadsheets we use had a fudge factor that someone inserted. Essentially, they added a value of 0.35 to a cost field (which is in the tens of thousands of dollars range). Given this is Excel we have no way of knowing who did it or when (probably to make it match some utility-provided tool value). But we didn't catch it for months. Only until we had a job where the cost was 100% covered by the utility, and the cost came out to $0.35, we caught it. This happened because it added 0.35 to 0 (the default value of an empty cell). If instead it printed NaN I would have ignored that price, and just put 0 in *at a later calculation* to prevent errors showing up in the final proposal. Then I would have missed the fudge factor someone sneaked in. The situations are completely dependent on the situation for *finding a problem*, for *diagnosing a problem* and for *fixing the problem*. It's impossible to predict how people will behave or how they will write code to cope with the situation they have. I think it's a wash in using either 0 or NaN for a default value when that value is incorrect. But I think in terms of *frequency*, a default value of 0 for a float that isn't explicitly initialized is 99% of the time correct, which means you will have *less of these problems to find*.
 
 
 I would start there to inspect variables, identify the NaNs.
What if you can't? What if it only happens randomly, and you don't just happen to have a debugger attached? I'm not saying it's easier with 0, but just not any different.
0.0 is hardly a rare value, even in correct calculations. NaN is always wrong.
It's not rare because it's a very very common initial value.
 
 
 Then I would trace them in a debugger and go up the call chain until 
 I find the location where it became NaN. Then I would identify the 
 source which introduced the NaN and trace that back until I found its 
 origin.
If you have a chance to use a debugger and it happens at that time.
0 initialization wouldn't make it better.
I will concede that if you have a debugger attached and can watch the things change in real time, seeing NaN show up can give you a better clue as to where the problem came from.
 
 
 The advantage I see in NaN is that it's always (instead of only 
 almost always) immediately obvious that it's wrong whereas 0.0 can be 
 valid or invalid so you need to figure out which one it is which 
 requires an extra step.
It might be noticed that it's NaN. It also might not. It depends on how it's used.
NaN propagates. 0.0 does not.
Someone has to look at it, to "obviously" see that it's wrong.
 
 
 Either way, you need to find the source, and NaN doesn't help unless 
 you want to start either instrumenting *all* code (possibly including 
 code you don't control), or use a debugger (which isn't always possible).
Such a situation is objectively worse with 0.0. Is instrumenting all the code to detect 0.0 going to work? Nope, too many false positives, as 0.0 is a common value for floating point numbers.
Either way, it's a mess. Better to just logically trace it based on where it's assigned from, instead of instrumenting, and trying to find NaNs in random places.
 
 
 Can we have some kind of linting system that identifies NaNs that are 
 used?
I have no objection to a linter that flags default initializations of floating point values. It shouldn't be part of the D compiler, though.
Something with semantic capabilities has to be used to prove it's not set before being used. Is there anything besides the compiler front end that can do this? -Steve
Aug 22 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/22/2022 6:16 PM, Steven Schveighoffer wrote:
 The point is, since 0.0 is a common value for a floating point value to be, 
 just when does it become obvious that it is wrong? Are you really going to 
 notice if your computation is 5% off? Isn't it a *lot* more obvious that it is 
 wrong if it is NaN?
This is a highly dependent situation. It could be 0, which is 100% off. It could be 5%. It could be 0.0001% off, which might actually not be a problem that is noticed.
Of course. And NaN is always wrong.
 If instead it printed NaN I would have ignored that price, and just put 0 in
*at 
 a later calculation* to prevent errors showing up in the final proposal. Then
I 
 would have missed the fudge factor someone sneaked in.
If you ignore the NaN value, you can hardly then blame it for missing the fudge factor.
 But I think in terms of *frequency*, a default value of 0 for a 
 float that isn't explicitly initialized is 99% of the time correct, which
means 
 you will have *less of these problems to find*.
See my other post about having code work by happenstance 99% of the time being not what D is about.
 0.0 is hardly a rare value, even in correct calculations. NaN is always wrong.
It's not rare because it's a very very common initial value.
0.0 a commonplace value everywhere.
 NaN propagates. 0.0 does not.
Someone has to look at it, to "obviously" see that it's wrong.
If you never look at the output, no bugs will be noticed in it anyway.
 Something with semantic capabilities has to be used to prove it's not set
before 
 being used. Is there anything besides the compiler front end that can do this?
You need data flow analysis for that. I didn't put DFA in the front end because that makes it slow for little benefit.
Aug 25 2022
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Tuesday, 23 August 2022 at 00:46:31 UTC, Walter Bright wrote:
 I have no objection to a linter that flags default 
 initializations of floating point values. It shouldn't be part 
 of the D compiler, though.
We already have a back end error (only when optimization is enabled) that detects null-dereference (or anything < address 4096): Object o; o.toHash; // Error: null dereference in function _Dmain Perhaps we could have a similar error for use of a default initialized floating-point variable?
Aug 27 2022
prev sibling parent reply drug007 <drug2004 bk.ru> writes:
On 8/22/22 14:41, Steven Schveighoffer wrote:
 On 8/21/22 12:51 PM, Walter Bright wrote:
 Consider the following pattern, which doesn't appear frequently, but 
 frequently enough:

      double x;
      if (condition) {
          x = 5;
          ...
      }
      ...               // (1)
      if (condition) {
         foo(x);
      }

 Imagine there's a lot more code omitted which obscures the pattern. 
 This code is correct.

 Now, maintainer adds `bar(x)` at (1).

 The scenarios:

 1. x is default initialized to NaN. bar(x) produces a NaN result on 
 everything dependent on x. User knows there's a problem.
How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?
For example, user has a callstack where called functions has these return values: float.init == 0 float.init == NaN 13 <== wrong result detected here ==> NaN 0 NaN 39 NaN 56 NaN 9 <== wrong initialization here ==> NaN 12 12 0 0 0 0 In which case you find the reason faster?
 
 2. x is default initialized to 0. bar(0) may exhibit problems, but 
 these problems won't necessarily be noticed.
Just like NaN.
No. NaN is not a number but zero is a number. zero may be both wrong and right value. NaN is never right result. To check if zero is right result you need manually calculate it. In case of NaN all you need is to take a look at it.
 
 3. compiler complains that `double x;` needs an initializer. To shut 
 up the compiler, the user initializes it to 0, without putting much 
 thought into it. bar(0) may exhibit problems, but these won't 
 necessarily be noticed.

 4. compiler complains that `double x;` needs an initializer. Coder 
 just schlepps in a 0. Yes, this happens. Maintainer wastes time 
 wondering why x is initialized to 0, as that may be a nonsense value 
 for x. Maintainer wonders if this unused initialization has a purpose, 
 maybe it is the result of a bad refactoring? Wastes more time 
 investigating it.
Huh? Why are there 2 identical situations here? I'll also point out that not initializing an integer is sometimes intentionally done (because it's equivalent to initializing to 0). If I see someone didn't assign a value to an int, I don't question if it was an accident, I expect that they meant it. Also, you forgot: 5. Maintainer expected x to default to 0 (because that's what most types do), and expected bar to be called with 0 or 5. Now, since bar saved the result of it's calculation elsewhere, and then far away from this code, the result is used in some computation that finally makes its way to output in some fashion (and possibly not a specific printing of the value), now there's a puzzle to solve, and no way to know it can be traced back to x without hours/days of searching.
 D chose option 1.
And there's probably no way that it changes. But in my mind the correct answer is to intialize to 0. -Steve
Aug 22 2022
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/22/22 9:33 AM, drug007 wrote:
 On 8/22/22 14:41, Steven Schveighoffer wrote:
 On 8/21/22 12:51 PM, Walter Bright wrote:
 Consider the following pattern, which doesn't appear frequently, but 
 frequently enough:

      double x;
      if (condition) {
          x = 5;
          ...
      }
      ...               // (1)
      if (condition) {
         foo(x);
      }

 Imagine there's a lot more code omitted which obscures the pattern. 
 This code is correct.

 Now, maintainer adds `bar(x)` at (1).

 The scenarios:

 1. x is default initialized to NaN. bar(x) produces a NaN result on 
 everything dependent on x. User knows there's a problem.
How? No exception is thrown, no error occurs. Unless bar somehow checks for NaN, nothing happens. Just like it is for 0. Perhaps it saves the result of bar computation to something for later use. Then that now gets propagated to some other use, and then, deep somewhere, NaN appears in something that appears completely unrelated to bar or x. How do you trace it back?
For example, user has a callstack where called functions has these return values: float.init == 0                float.init == NaN     13 <==  wrong result detected here  ==> NaN     0                     NaN     39                    NaN     56                    NaN     9 <==   wrong initialization here   ==> NaN     12                    12     0                     0     0                     0 In which case you find the reason faster?
Callstack printouts don't look like that. Plus, what if you don't have the call stack available for inspection? And even if you do, that 9 might be just as obviously wrong as the NaN, negating any real benefit. One thing that everyone seems to be ignoring is that 99% of the time, when I find out I didn't initialize a float and it's NaN, it's because I didn't correctly initialize it to 0. So yes, when a lack of initialization somewhere in some code has happened *and is a mistake*, a NaN starting value can make things slightly easier, as long as you have everything instrumented, and can use a debugger. But *when* it happens is reduced to near zero if the default value is the expected 0.
 2. x is default initialized to 0. bar(0) may exhibit problems, but 
 these problems won't necessarily be noticed.
Just like NaN.
No. NaN is not a number but zero is a number. zero may be both wrong and right value. NaN is never right result. To check if zero is right result you need manually calculate it. In case of NaN all you need is to take a look at it.
As I've mentioned, you don't always see the NaN, just like you don't always see the 0. Imagine you are making a 3-d model, and one vertex out of 100k is NaN. How will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious. -Steve
Aug 22 2022
next sibling parent drug007 <drug2004 bk.ru> writes:
On 8/22/22 17:16, Steven Schveighoffer wrote:
 On 8/22/22 9:33 AM, drug007 wrote:
 For example, user has a callstack where called functions has these 
 return values:

 float.init == 0                float.init == NaN

      13 <==  wrong result detected here  ==> NaN
      0                     NaN
      39                    NaN
      56                    NaN
      9 <==   wrong initialization here   ==> NaN
      12                    12
      0                     0
      0                     0

 In which case you find the reason faster?
Callstack printouts don't look like that. Plus, what if you don't have
Of course it is not a real call stack
 the call stack available for inspection? And even if you do, that 9 
you can use printf debugging
 might be just as obviously wrong as the NaN, negating any real benefit.
Yes, that's the point! 9 might be obviously. But NaN would be obviously.
 One thing that everyone seems to be ignoring is that 99% of the time, 
 when I find out I didn't initialize a float and it's NaN, it's because I 
 didn't correctly initialize it to 0.
 
I don't agree. There are cases where default initialization is non-zero.
 So yes, when a lack of initialization somewhere in some code has 
 happened *and is a mistake*, a NaN starting value can make things 
 slightly easier, as long as you have everything instrumented, and can 
 use a debugger. But *when* it happens is reduced to near zero if the 
 default value is the expected 0.
 
you are exaggregating a little. instrumentation is not required and printf debugging is always available
 2. x is default initialized to 0. bar(0) may exhibit problems, but 
 these problems won't necessarily be noticed.
Just like NaN.
No. NaN is not a number but zero is a number. zero may be both wrong and right value. NaN is never right result. To check if zero is right result you need manually calculate it. In case of NaN all you need is to take a look at it.
As I've mentioned, you don't always see the NaN, just like you don't always see the 0. Imagine you are making a 3-d model, and one vertex out of 100k is NaN. How will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious.
Yes, in this specific case you right. But what if some of your valid vertices might be zero too?
 -Steve
Aug 22 2022
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/22/22 07:16, Steven Schveighoffer wrote:

 One thing that everyone seems to be ignoring is that 99% of the time,
 when I find out I didn't initialize a float and it's NaN, it's because I
 didn't correctly initialize it to 0.
Although Walter has already said it on this thread, what is missing in this picture is, 63% of the time we would not even know we had bugs if D picked the default value to be 0.0.[1] I bet I can find bugs related to initialization in 12% of production C++ programs that use floating point variables. Ali [1] Yes, I made 63% up. [2] I made that up as well but I am more confident in that figure. :o)
Aug 23 2022
prev sibling next sibling parent wjoe <invalid example.com> writes:
On Monday, 22 August 2022 at 14:16:14 UTC, Steven Schveighoffer 
wrote:
 Imagine you are making a 3-d model, and one vertex out of 100k 
 is NaN. How will you notice it? A single missing triangle 
 somewhere?

 But make that vertex 0, and all of a sudden your model has this 
 weird triangle sticking out extending to the origin, and is 
 completely obvious.

 -Steve
It could just as well be a very obvious hole, as easy to make out as that spike. Also that number may not end up being 0 so the spike may be very subtle. If I wouldn't notice, i.e. neither visibly nor due to a performance impact, I probably wouldn't even start looking. I've seen these spikes due to errors in hardware or operating it outside specifications (over clocking, under volting), too. But the artifact needn't necessarily be a triangle. Could be a color or transparency channel. A NaN value is incorrect - would you know the same if it's any real number ? Or would you have to ask the artist ? Would you even notice ? It may be off by just 0.35 in the blue channel - the eye is very insensitive to blue. It may not be obvious because of color blindness, or the monitor isn't calibrated to the color space, or any amount of different reasons. But someone else may notice and send a bug report and when you start investigating, a NaN will tell you the truth even if you can't visually see it yourself. In shapes it may be more obvious but anything in art goes and NaN is still always wrong. It's like a math professor asking their students to name the highest number they know and professor is going to provide a higher number. Next thing that happens is that someone calls "infinity" - infinity isn't a number. Maybe the situation could be improved in that the compiler adds checks for NaN akin to bounds checking and throws a NaN_Error. This way the error could be caught even before sending wrong data to the GPU - or whatever API.
Aug 23 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/22/2022 7:16 AM, Steven Schveighoffer wrote:
 One thing that everyone seems to be ignoring is that 99% of the time, when I 
 find out I didn't initialize a float and it's NaN, it's because I didn't 
 correctly initialize it to 0.
Then 1% of the time 0 is the wrong value and you never notice that the resulting calculation is off. Whereas with NaN you notice that when there's "NaN" in the printed result, it's not hiding.
 Imagine you are making a 3-d model, and one vertex out of 100k is NaN. How 
will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious. C89 did not take NaNs into account for the floating point parts of the C standard library. But C99 did, and if the program tries to calculate: sin(NaN) the result will be NaN, guaranteed by the C99 Standard. If the graphics library cannot handle certain floating point values, such as NaN or Infinity, then that should be checked for as part of the call. At least in debug builds. It'll be a lot easier than looking for an out of place triangle. Most graphical displays seem to have an awful lot of tiny triangles. If I was writing code that, say, calculated a trajectory of a space craft, there is no way it would be acceptable to have default 0 initialization. Even if it's right 99% of the time. Because 1% of the time having a hull loss is not acceptable. P.S. graphics software generally doesn't care about making mistakes. I've seen plenty of buggy graphics in video games, and it doesn't matter because it doesn't affect game play. But people doing science, engineering, accounting, flight controls, etc., care very much about getting 100% correct results. 1% going awry is not acceptable.
Aug 23 2022
parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Wednesday, 24 August 2022 at 05:54:59 UTC, Walter Bright wrote:
 On 8/22/2022 7:16 AM, Steven Schveighoffer wrote:
 One thing that everyone seems to be ignoring is that 99% of 
 the time, when I find out I didn't initialize a float and it's 
 NaN, it's because I didn't correctly initialize it to 0.
Then 1% of the time 0 is the wrong value and you never notice that the resulting calculation is off. Whereas with NaN you notice that when there's "NaN" in the printed result, it's not hiding.
 Imagine you are making a 3-d model, and one vertex out of
100k is NaN. How will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious. C89 did not take NaNs into account for the floating point parts of the C standard library. But C99 did, and if the program tries to calculate: sin(NaN) the result will be NaN, guaranteed by the C99 Standard. If the graphics library cannot handle certain floating point values, such as NaN or Infinity, then that should be checked for as part of the call. At least in debug builds. It'll be a lot easier than looking for an out of place triangle. Most graphical displays seem to have an awful lot of tiny triangles. If I was writing code that, say, calculated a trajectory of a space craft, there is no way it would be acceptable to have default 0 initialization. Even if it's right 99% of the time. Because 1% of the time having a hull loss is not acceptable. P.S. graphics software generally doesn't care about making mistakes. I've seen plenty of buggy graphics in video games, and it doesn't matter because it doesn't affect game play. But people doing science, engineering, accounting, flight controls, etc., care very much about getting 100% correct results. 1% going awry is not acceptable.
That's the best answer possible, i used to be annoyed by float not being 0 by default, but as i learn more and read different takes on it, it makes sense, and i don't mind anymore The main issue is to get used to it, it takes time if you use other languages that defaults to 0
Aug 24 2022
next sibling parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Wednesday, 24 August 2022 at 18:11:57 UTC, ryuukk_ wrote:
 On Wednesday, 24 August 2022 at 05:54:59 UTC, Walter Bright 
 wrote:
 On 8/22/2022 7:16 AM, Steven Schveighoffer wrote:
 One thing that everyone seems to be ignoring is that 99% of 
 the time, when I find out I didn't initialize a float and 
 it's NaN, it's because I didn't correctly initialize it to 0.
Then 1% of the time 0 is the wrong value and you never notice that the resulting calculation is off. Whereas with NaN you notice that when there's "NaN" in the printed result, it's not hiding.
 Imagine you are making a 3-d model, and one vertex out of
100k is NaN. How will you notice it? A single missing triangle somewhere? But make that vertex 0, and all of a sudden your model has this weird triangle sticking out extending to the origin, and is completely obvious. C89 did not take NaNs into account for the floating point parts of the C standard library. But C99 did, and if the program tries to calculate: sin(NaN) the result will be NaN, guaranteed by the C99 Standard. If the graphics library cannot handle certain floating point values, such as NaN or Infinity, then that should be checked for as part of the call. At least in debug builds. It'll be a lot easier than looking for an out of place triangle. Most graphical displays seem to have an awful lot of tiny triangles. If I was writing code that, say, calculated a trajectory of a space craft, there is no way it would be acceptable to have default 0 initialization. Even if it's right 99% of the time. Because 1% of the time having a hull loss is not acceptable. P.S. graphics software generally doesn't care about making mistakes. I've seen plenty of buggy graphics in video games, and it doesn't matter because it doesn't affect game play. But people doing science, engineering, accounting, flight controls, etc., care very much about getting 100% correct results. 1% going awry is not acceptable.
That's the best answer possible, i used to be annoyed by float not being 0 by default, but as i learn more and read different takes on it, it makes sense, and i don't mind anymore The main issue is to get used to it, it takes time if you use other languages that defaults to 0
I want to point out that, just like with the GC, it is not the panacea, if you have a NaN in your result, good luck finding what is the root of the issue/bug in your program, or library.. it is during moments like that that i still prefer it being 0 by default, so everyone is on the same page
Aug 24 2022
next sibling parent ryuukk_ <ryuukk.dev gmail.com> writes:
On Wednesday, 24 August 2022 at 18:15:53 UTC, ryuukk_ wrote:
 I want to point out that, just like with the GC, it is not the 
 panacea, if you have a NaN in your result, good luck finding 
 what is the root of the issue/bug in your program, or library.. 
 it is during moments like that that i still prefer it being 0 
 by default, so everyone is on the same page
One could say, "well that's a bug anyways, and now you know you got a bug in your program", and that's why NaN wins over 0, it's annoying, but it is useful (sorry for 3 successive reply)
Aug 24 2022
prev sibling next sibling parent reply user1234 <user1234 12.de> writes:
On Wednesday, 24 August 2022 at 18:15:53 UTC, ryuukk_ wrote:
 I want to point out that, just like with the GC, it is not the 
 panacea, if you have a NaN in your result, good luck finding 
 what is the root of the issue/bug in your program, or library.. 
 it is during moments like that that i still prefer it being 0 
 by default, so everyone is on the same page
In gdb you can use `select-frame` and inspect the value of locals of the **whole** call stack. Also just `bt` can help as that shows the call args values.
Aug 24 2022
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/24/22 4:07 PM, user1234 wrote:
 On Wednesday, 24 August 2022 at 18:15:53 UTC, ryuukk_ wrote:
 I want to point out that, just like with the GC, it is not the 
 panacea, if you have a NaN in your result, good luck finding what is 
 the root of the issue/bug in your program, or library.. it is during 
 moments like that that i still prefer it being 0 by default, so 
 everyone is on the same page
In gdb you can use `select-frame` and inspect the value of locals of the **whole** call stack. Also just `bt` can help as that shows the call args values.
The source may not be in the call stack. -Steve
Aug 24 2022
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/24/2022 11:15 AM, ryuukk_ wrote:
 I want to point out that, just like with the GC, it is not the panacea, if you 
 have a NaN in your result, good luck finding what is the root of the issue/bug 
 in your program, or library.. it is during moments like that that i still
prefer 
 it being 0 by default, so everyone is on the same page
I can't think of a case where a 0 is easier to track back to its origin.
Aug 24 2022
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/24/2022 11:11 AM, ryuukk_ wrote:
 That's the best answer possible, i used to be annoyed by float not being 0 by 
 default, but as i learn more and read different takes on it, it makes sense,
and 
 i don't mind anymore
 
 The main issue is to get used to it, it takes time if you use other languages 
 that defaults to 0
It's one reason why D is simply better than those other languages. (Not many language designers have experience doing commercial floating point work, and it shows. I was an early member of NCEG (Numerical C Extensions Group) which worked hard to add proper floating point support to the C Standard, including exacting support for NaN. I implemented it in Zortech C/C++ years before anyone else did.)
Aug 24 2022
prev sibling next sibling parent Guillaume Piolat <first.last spam.org> writes:
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:
 As someone coming from Java to use D, I find it myself quite 
 annoying that float and double are initialized to `nan`.
Honestly have no opinion on float.init being NaN, I don't think I would care either way.
Aug 21 2022
prev sibling parent reply Dave P. <dave287091 gmail.com> writes:
On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:
 [...]
What’s great is that structs defined in C imported in D and structs defined in D imported in D will have completely different initial values despite being syntactically identical! ```D // foo_c.c struct Foo { float x; }; // foo_d.d struct Foo { float x; }; // main.d import foo_d; import foo_c; import std.stdio: writeln; void main(){ foo_d.Foo f_d; foo_c.Foo f_c; writeln(f_d); // Foo(nan) writeln(f_c); // Foo(0) } ```
Aug 23 2022
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/23/22 13:44, Dave P. wrote:
 On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:
 [...]
 will have completely different initial values
Although C does not initialize variables, sometimes both C and D floats can have the same exact bit pattern.
 despite being syntactically identical!
C and D are different languages.
      writeln(f_d); // Foo(nan)
That will always be the case.
      writeln(f_c); // Foo(0)
And yes, 0 happens to be a valid garbage value. Ali
Aug 23 2022
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/23/22 5:24 PM, Ali Çehreli wrote:
 Although C does not initialize variables, sometimes both C and D floats 
 can have the same exact bit pattern.
I'm wondering if D does not zero-initialize structs that are from importC? -Steve
Aug 23 2022
prev sibling parent reply Dave P. <dave287091 gmail.com> writes:
On Tuesday, 23 August 2022 at 21:24:10 UTC, Ali Çehreli wrote:
 On 8/23/22 13:44, Dave P. wrote:
 On Friday, 19 August 2022 at 13:42:58 UTC, Hipreme wrote:
 [...]
 will have completely different initial values
Although C does not initialize variables, sometimes both C and D floats can have the same exact bit pattern.
 despite being syntactically identical!
C and D are different languages.
This is a struct defined in C being used in D via ImportC.
      writeln(f_d); // Foo(nan)
That will always be the case.
      writeln(f_c); // Foo(0)
And yes, 0 happens to be a valid garbage value.
The default value for a struct imported via importC is all bits 0. This is not a “garbage value”.
Aug 23 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/23/22 14:40, Dave P. wrote:

 And yes, 0 happens to be a valid garbage value.
The default value for a struct imported via importC is all bits 0.
Steve said the same thing but I don't see it on the ImportC page (yet?): https://dlang.org/spec/importc.html I wonder why D would do that.
 This is not a “garbage value”.
D could set all bits to any other value and it would still be fine because either C's initialization function would be called on the object (some programmers call memset), or the programmer did not care. Ali
Aug 23 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 23 August 2022 at 21:53:35 UTC, Ali Çehreli wrote:
 On 8/23/22 14:40, Dave P. wrote:

 And yes, 0 happens to be a valid garbage value.
The default value for a struct imported via importC is all
bits 0. Steve said the same thing but I don't see it on the ImportC page (yet?): https://dlang.org/spec/importc.html I wonder why D would do that.
Global and static variables in C are initialized to all-zero bits, regardless of type. Here's the relevant paragraph from the C11 standard:
 If an object that has automatic storage duration is not 
 initialized explicitly, its value is indeterminate. If an 
 object that has static or thread storage duration is not 
 initialized explicitly, then:
 
     if it has pointer type, it is initialized to a null pointer;
     if it has arithmetic type, it is initialized to (positive 
 or unsigned) zero;
     if it is an aggregate, every member is initialized 
 (recursively) according to these rules, and any padding is 
 initialized to zero bits;
     if it is a union, the first named member is initialized 
 (recursively) according to these rules, and any padding is 
 initialized to zero bits;
Presumably this behavior was implemented in an attempt to conform to this part of the C standard.
Aug 23 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/23/2022 4:35 PM, Paul Backus wrote:
 Presumably this behavior was implemented in an attempt to conform to this part 
 of the C standard.
Yes. It's not a bug.
Aug 23 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/23/2022 1:44 PM, Dave P. wrote:
 What’s great is that structs defined in C imported in D and structs defined
in D 
 imported in D will have completely different initial values despite being 
 syntactically identical!
Let's have some fun with the following C program: ----------- #include <stdio.h> struct Foo { float x; }; int main() { struct Foo f; printf("%g\n", f.x); } gcc test.c ./a.out 2.12133e-15 ------------- Oh well!
Aug 23 2022
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/23/22 6:33 PM, Walter Bright wrote:
 On 8/23/2022 1:44 PM, Dave P. wrote:
 What’s great is that structs defined in C imported in D and structs 
 defined in D imported in D will have completely different initial 
 values despite being syntactically identical!
Let's have some fun with the following C program: -----------  #include <stdio.h>  struct Foo { float x; };  int main()  {     struct Foo f;     printf("%g\n", f.x);  }  gcc test.c  ./a.out  2.12133e-15 ------------- Oh well!
Since you are looking at it, the original code is *not* a C function, it's a D function using a struct defined using C (imported via ImportC). What happens in that case? On one hand, it's a C struct. But on the other hand, it's a D function. Who's rules are used? -Steve
Aug 23 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/23/2022 5:00 PM, Steven Schveighoffer wrote:
 On one hand, it's a C struct. But on the other hand, it's a D function. Who's 
 rules are used?
The C rules. This is because D is importing C code, so it better behave like C code. C code does initialize floats and doubles to 0.0 if they are placed in static data. It is not reasonable that D would leave imported C structures uninitialized when C does, and so initializing them to 0.0 is a reasonable choice.
Aug 23 2022
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/24/22 1:14 AM, Walter Bright wrote:
 On 8/23/2022 5:00 PM, Steven Schveighoffer wrote:
 On one hand, it's a C struct. But on the other hand, it's a D 
 function. Who's rules are used?
The C rules. This is because D is importing C code, so it better behave like C code. C code does initialize floats and doubles to 0.0 if they are placed in static data. It is not reasonable that D would leave imported C structures uninitialized when C does, and so initializing them to 0.0 is a reasonable choice.
So to paraphrase this, D does initialize local C structure values, but initializes doubles/floats to 0 to be consistent with C static initialization. In other words, it *doesn't* use the C rules of not initializing locals that have no explicit initialization. But it *does* use the C rules of what value to initialize with. I actually proved this too with a test, so that's good news! Maybe I just need to define all my structs using C :P -Steve
Aug 24 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/24/2022 7:03 AM, Steven Schveighoffer wrote:
 I actually proved this too with a test, so that's good news! Maybe I just need 
 to define all my structs using C :P
You could, but NaN default initialization is better. I inferred that you relied on detecting a wrong 0 initialization by looking for unexpected behavior. This is less reliable than looking for a NaN in the output. When the behavior of a mistake being most of the time it will work out ok, is not acceptable because there's that case where it won't be ok and could be very costly. It should not be "the output looks sort of right, so assume it is right." It should *be* right, or be *obviously* wrong. People should have to explicitly work at getting it wrong. These are more of those lessons I picked up from working on flight controls at Boeing. For example, hydraulic actuators (rams) drive the flight control surfaces back and forth. The actuators have a hydraulic fluid input port, and an output port. If the hydraulic lines are hooked to the wrong ports, the airplane will be uncontrollable and will crash. This has happened many times in the past. Boeing's solution is to: 1. the ports are different sizes 2. one is a left-hand thread, the other is a right-hand thread 3. the lines and ports are color-coded 4. the lines are laid out so the hydraulic lines are not long enough to connect to the wrong port 5. inspectors have to sign off on it 6. the flight controls are tested for correct operation as part of the pre-flight checklist This has stopped the problem. Note how hard a mechanic would have to work to get it wrong, and if he succeeded it would be *obviously* wrong to the inspector. I try to infuse this philosophy into D's design where ever it fits.
Aug 24 2022
next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 25 August 2022 at 01:19:55 UTC, Walter Bright wrote:
 If the hydraulic lines are hooked to the wrong ports, the 
 airplane will be uncontrollable and will crash.
oh ye of little faith! I read about a story where this happened. The pilots quickly found the plane uncontrollable to the point where they asked for vectors to ditch into the ocean so the crash wouldn't hurt anybody on the ground at least... but they couldn't even control it well enough to successfully navigate out there. They kept flying in random directions and ended up over ground again, but had enough altitude to keep trying again. After quite some time though, they actually recognized the "random, uncontrollable" aircraft actually was responding to their inputs in a predictable pattern, it was just all messed up. As they figured it out and learned how to fly with these bizarro controls, their initial panic subsided and they were able to successfully return to the airport for a safe landing! (of course there are other similar stories without the happy ending so your point is good, but i like this story)
Aug 24 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/24/2022 6:30 PM, Adam D Ruppe wrote:
 On Thursday, 25 August 2022 at 01:19:55 UTC, Walter Bright wrote:
 If the hydraulic lines are hooked to the wrong ports, the airplane will be 
 uncontrollable and will crash.
oh ye of little faith! I read about a story where this happened. The pilots quickly found the plane uncontrollable to the point where they asked for vectors to ditch into the ocean so the crash wouldn't hurt anybody on the ground at least... but they couldn't even control it well enough to successfully navigate out there. They kept flying in random directions and ended up over ground again, but had enough altitude to keep trying again. After quite some time though, they actually recognized the "random, uncontrollable" aircraft actually was responding to their inputs in a predictable pattern, it was just all messed up. As they figured it out and learned how to fly with these bizarro controls, their initial panic subsided and they were able to successfully return to the airport for a safe landing! (of course there are other similar stories without the happy ending so your point is good, but i like this story)
The cases I've heard all resulted in a smoking hole in the ground just past the end of the runway. When the airplane does the wrong thing as the result of a control input, the natural pilot reflex is to push it harder, not try the other way. When you're a few feet off the ground, that means smacking it hard into the ground. Your anecdote was surely not the elevators or ailerons. It might have been the rudder, where the pilots would have more of a chance.
Aug 25 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 25 August 2022 at 16:36:41 UTC, Walter Bright wrote:
 Your anecdote was surely not the elevators or ailerons. It 
 might have been the rudder, where the pilots would have more of 
 a chance.
I found the story again, here's the wikipedia article on it that has its references too: https://en.wikipedia.org/wiki/Air_Astana_Flight_1388 "The investigation revealed that the aileron cables were installed incorrectly." Only a few years ago too, in 2018! There's youtube videos too talking about it too: https://www.youtube.com/watch?v=5ywaMkMTwWk (this guy generally goes over the incident report with some nice animations to explain it too) https://www.youtube.com/watch?v=kIc8Rr-cKd8 (atc recording part 1) https://www.youtube.com/watch?v=evYLkhxoP3U (part 2) i know im pretty far off topic but i just enjoy these aviation things.
Aug 25 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
Thanks for the reference. I'm always interested in these kinds of things. I'm 
surprised blame wasn't also placed on the design for making it possible to 
reverse the controls.

I'm amazed they managed to land it successfully. Those pilots ought to get a 
medal for flying skill, along with the brickbats for failing to preflight the 
airplane properly.

Probably the only reason they didn't crash it was the spoilers were set up 
correctly, and countered some of the aileron bad movement.

On 8/25/2022 10:32 AM, Adam D Ruppe wrote:
 I found the story again, here's the wikipedia article on it that has its 
 references too:
 
 https://en.wikipedia.org/wiki/Air_Astana_Flight_1388
 
 "The investigation revealed that the aileron cables were installed
incorrectly."
 
 Only a few years ago too, in 2018!
 
 There's youtube videos too talking about it too:
 
 https://www.youtube.com/watch?v=5ywaMkMTwWk (this guy generally goes over the 
 incident report with some nice animations to explain it too)
 https://www.youtube.com/watch?v=kIc8Rr-cKd8 (atc recording part 1)
 https://www.youtube.com/watch?v=evYLkhxoP3U (part 2)
 
 i know im pretty far off topic but i just enjoy these aviation things.
Aug 25 2022
prev sibling next sibling parent zjh <fqbqrr 163.com> writes:
On Thursday, 25 August 2022 at 01:19:55 UTC, Walter Bright wrote:
 Boeing.
Now Boeing is a fighter among missiles.
Aug 24 2022
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/24/22 9:19 PM, Walter Bright wrote:
 On 8/24/2022 7:03 AM, Steven Schveighoffer wrote:
 I actually proved this too with a test, so that's good news! Maybe I 
 just need to define all my structs using C :P
You could, but NaN default initialization is better. I inferred that you relied on detecting a wrong 0 initialization by looking for unexpected behavior. This is less reliable than looking for a NaN in the output. When the behavior of a mistake being most of the time it will work out ok, is not acceptable because there's that case where it won't be ok and could be very costly.
No, you are completely misunderstanding what I'm saying. What I was saying is that NaN is not that much different from 0 when the outputs you have aren't "val = NaN". I.e. most of the time. Once you have determined there is a problem, I don't really think NaN helps much finding the source -- the source can be long gone by the time you attach a debugger. The correct mechanism is to look at what possible places the value could be written, and trace it back to the incorrect value. But what I *am* saying is that I frequently omit initialization of numbers I expect to start at 0. I forget that double is NaN by default, and then I have to find and fix that. The only thing NaN has ever done for me is found places where I forgot to initialize to 0.
 
 It should not be "the output looks sort of right, so assume it is 
 right." It should *be* right, or be *obviously* wrong.
 
 People should have to explicitly work at getting it wrong.
 
 These are more of those lessons I picked up from working on flight 
 controls at Boeing.
NaN fails at that. It's silently swallowed by just about everything. Only when a human looks at some printout does it become obvious. A better option would be to throw an exception if NaN is used in an operation.
 For example, hydraulic actuators (rams) drive the flight control 
 surfaces back and forth. The actuators have a hydraulic fluid input 
 port, and an output port. If the hydraulic lines are hooked to the wrong 
 ports, the airplane will be uncontrollable and will crash. This has 
 happened many times in the past. Boeing's solution is to:
 
 1. the ports are different sizes
 2. one is a left-hand thread, the other is a right-hand thread
 3. the lines and ports are color-coded
 4. the lines are laid out so the hydraulic lines are not long enough to 
 connect to the wrong port
 5. inspectors have to sign off on it
 6. the flight controls are tested for correct operation as part of the 
 pre-flight checklist
 
 This has stopped the problem. Note how hard a mechanic would have to 
 work to get it wrong, and if he succeeded it would be *obviously* wrong 
 to the inspector.
 
 I try to infuse this philosophy into D's design where ever it fits.
I understand, but NaN is woefully inadequate for the task. NaN is more like if you hooked up the ports wrong, a dye is added to the fluid, which isn't visible through the tubes. You have to extract and examine the fluid to realize something is wrong. Then you have to find the source of the dye (and it could come from anywhere in the system). -Steve
Aug 24 2022
next sibling parent reply bauss <jacobbauss gmail.com> writes:
On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer 
wrote:
 A better option would be to throw an exception if NaN is used 
 in an operation.

 -Steve
IMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.) This will solve all problems because: - You will never have a NaN value propagate throughout your program, making it much easier to track it back to its roots. - NaN strictly tells you that some value is wrong before it's even being used - There's no way to workaround it effectively, meaning you must actually fix any places where NaN is possible.
Aug 25 2022
parent reply user1234 <user12342 12.de> writes:
On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:
 On Thursday, 25 August 2022 at 03:08:54 UTC, Steven 
 Schveighoffer wrote:
 A better option would be to throw an exception if NaN is used 
 in an operation.

 -Steve
IMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.)
I'm shocked by this idea. What if I want high performance nothrow FP code ?
Aug 25 2022
next sibling parent bauss <jacobbauss gmail.com> writes:
On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:
 On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:
 On Thursday, 25 August 2022 at 03:08:54 UTC, Steven 
 Schveighoffer wrote:
 A better option would be to throw an exception if NaN is used 
 in an operation.

 -Steve
IMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.)
I'm shocked by this idea. What if I want high performance nothrow FP code ?
It could be optimized away in release code and/or be optional to disable (should be enabled by default.)
Aug 25 2022
prev sibling parent reply max haughton <maxhaton gmail.com> writes:
On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:
 On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:
 On Thursday, 25 August 2022 at 03:08:54 UTC, Steven 
 Schveighoffer wrote:
 A better option would be to throw an exception if NaN is used 
 in an operation.

 -Steve
IMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.)
I'm shocked by this idea. What if I want high performance nothrow FP code ?
Turn the check off. The hardware basically already supports doing this (NaNs don't have to be quiet) but almost no one uses it - it's quite hard to trigger at all on a modern system.
Aug 25 2022
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 25 August 2022 at 11:38:22 UTC, max haughton wrote:
 On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:
 On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:
 On Thursday, 25 August 2022 at 03:08:54 UTC, Steven 
 Schveighoffer wrote:
 A better option would be to throw an exception if NaN is 
 used in an operation.

 -Steve
IMHO this is the better solution and not even an exception, but Error. As soon as you have any NaN values that are being used your program is effectively useless and broken. I think as soon as any variable becomes NaN it should throw, not just when an operation happens. Basically I think it should throw when either of these conditions holds true: - A value was initialized as NaN and used in an operation - A value was set to NaN outside of initialization - NaN is returned from a function (Even if not set to a variable or anything.)
I'm shocked by this idea. What if I want high performance nothrow FP code ?
Turn the check off. The hardware basically already supports doing this (NaNs don't have to be quiet) but almost no one uses it - it's quite hard to trigger at all on a modern system.
Looks like D allows you to enable floating-point exceptions using the [`std.math.hardware.FloatingPointControl`][1] interface. Of course, these are hardware exceptions, so you will get SIGFPE rather than a thrown Error with a backtrace. To turn them into D Errors you'd need to set up a signal handler, like how `etc.linux.memoryerror` does it (or whatever the equivalent is on Windows). [1]: https://phobos.dpldocs.info/std.math.hardware.FloatingPointControl.html
Aug 25 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 25 August 2022 at 14:34:52 UTC, Paul Backus wrote:
 Looks like D allows you to enable floating-point exceptions 
 using the [`std.math.hardware.FloatingPointControl`][1] 
 interface.

 Of course, these are hardware exceptions, so you will get 
 SIGFPE rather than a thrown Error with a backtrace. To turn 
 them into D Errors you'd need to set up a signal handler, like 
 how `etc.linux.memoryerror` does it (or whatever the equivalent 
 is on Windows).

 [1]: 
 https://phobos.dpldocs.info/std.math.hardware.FloatingPointControl.html
Unfortunately, it looks like this will not work in practice, because the "invalid" floating-point exception is raised only when a NaN is *created*, not when it's *propagated*. Since the initial NaN values of default-initialized `float`/`double` variables are created at compile time, not runtime, no exception is ever raised for them. Example program: ```d import std.math.hardware; float div(float x, float y) { return x / y; } void main() { FloatingPointControl fpctrl; fpctrl.enableExceptions(FloatingPointControl.severeExceptions); float f = float.nan; // ok - no exception float g = div(0.0f, 0.0f); // crashes with SIGFPE } ```
Aug 25 2022
parent reply IGotD- <nise nise.com> writes:
On Thursday, 25 August 2022 at 16:06:43 UTC, Paul Backus wrote:
 Unfortunately, it looks like this will not work in practice, 
 because the "invalid" floating-point exception is raised only 
 when a NaN is *created*, not when it's *propagated*. Since the 
 initial NaN values of default-initialized `float`/`double` 
 variables are created at compile time, not runtime, no 
 exception is ever raised for them.
Which is strange because HW wise it is trivial to check if the result is NaN. To check that NaN is not based on input is of course more complicated. Then again an x86 complicated in an unhealthy way. This kind of makes another motivation to let floats default to zero, if this is correct.
Aug 25 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/25/2022 9:16 AM, IGotD- wrote:
 Which is strange because HW wise it is trivial to check if the result is NaN.
To 
 check that NaN is not based on input is of course more complicated. Then again 
 an x86 complicated in an unhealthy way.
 
 This kind of makes another motivation to let floats default to zero, if this
is 
 correct.
There's nothing to be afraid of in getting a NaN in the output. One should be glad, because then one *knows* there's a bug. This thread reminds me of the threads about assert, and the contention that the program should continue after a failed assert. 1. It is not better to pretend a program is working when it is not. 2. It is not better for a language to guess at what the programmer must have meant, even if the guess is correct 99% of the time. 3. It is not better to never check the output of the program for correctness. D is a tool for helping the programmer create correct, robust, and bug-free programs.
Aug 25 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 25.08.22 18:56, Walter Bright wrote:
 On 8/25/2022 9:16 AM, IGotD- wrote:
 Which is strange because HW wise it is trivial to check if the result 
 is NaN. To check that NaN is not based on input is of course more 
 complicated. Then again an x86 complicated in an unhealthy way.

 This kind of makes another motivation to let floats default to zero, 
 if this is correct.
There's nothing to be afraid of in getting a NaN in the output. One should be glad, because then one *knows* there's a bug. This thread reminds me of the threads about assert, and the contention that the program should continue after a failed assert. ...
Clearly you should throw away your computer after a failed assert.
 1. It is not better to pretend a program is working when it is not.
 
 2. It is not better for a language to guess at what the programmer must 
 have meant, even if the guess is correct 99% of the time.
 
 3. It is not better to never check the output of the program for 
 correctness.
 
 D is a tool for helping the programmer create correct, robust, and 
 bug-free programs.
Which is why asserts can introduce new _undefined behavior_?
Aug 29 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/29/2022 5:27 PM, Timon Gehr wrote:
 Clearly you should throw away your computer after a failed assert.
Absolutely. My basement is full of junked computers that dared to fail.
 Which is why asserts can introduce new _undefined behavior_?
DMD has a switch to insert a halt instruction upon assertion failures.
Aug 30 2022
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 30.08.22 17:47, Walter Bright wrote:
 On 8/29/2022 5:27 PM, Timon Gehr wrote:
 Clearly you should throw away your computer after a failed assert.
Absolutely. My basement is full of junked computers that dared to fail.
 Which is why asserts can introduce new _undefined behavior_?
DMD has a switch to insert a halt instruction upon assertion failures.
Let's assume whoever is compiling my code does not want to spend computational resources on checking my asserts. (Or invariants, etc.) My problem is that DMD seems to _lack_ switches to _safely_ disable checking (as far as I understand; it's notoriously underdocumented). The fact that something that's called "turn off checking" will introduce UB is just really bad UX design. You are nothing short of ensuring that the hydraulic lines are hooked to the wrong ports. Aside: My experience with people running into "Illegal instruction" is that they just assume the compiler has a bug and produced invalid machine code. Also, the semantics of "hlt" is not to terminate anything at all, it just waits for the next interrupt to be fired. The only reason it crashes in user space is that it requires ring 0 access.
Aug 30 2022
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 31 August 2022 at 02:05:21 UTC, Timon Gehr wrote:
 Also, the semantics of "hlt" is not to terminate anything at all
It actually uses UD2 now (I've been complaining about this for years and it actually got changed in Dec 2017, so long time ago, but Walter's old habits die hard) https://github.com/dlang/dmd/pull/7391
Aug 30 2022
prev sibling parent "H. S. Teoh" <hsteoh qfbox.info> writes:
On Wed, Aug 31, 2022 at 04:05:21AM +0200, Timon Gehr via Digitalmars-d wrote:
[...]
 Also, the semantics of "hlt" is not to terminate anything at all, it
 just waits for the next interrupt to be fired. The only reason it
 crashes in user space is that it requires ring 0 access.
Hmm. I was pretty sure the convention, at least on x86 architectures, is that hlt in userspace is a signal to the OS that the program has terminated itself (usually abnormally, since normal termination is usually via the exit syscall, at least on Posix). T -- It won't be covered in the book. The source code has to be useful for something, after all. -- Larry Wall
Aug 30 2022
prev sibling parent user1234 <user12342 12.de> writes:
On Thursday, 25 August 2022 at 11:38:22 UTC, max haughton wrote:
 On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:
 On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:
 [...]
I'm shocked by this idea. What if I want high performance nothrow FP code ?
Turn the check off. The hardware basically already supports doing this (NaNs don't have to be quiet) but almost no one uses it - it's quite hard to trigger at all on a modern system.
We agree there, we talk about a check that does not even exist but that has to be disabled.
Aug 25 2022
prev sibling next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer 
wrote:
 by default, and then I have to find and fix that. The only 
 thing NaN has ever done for me is found places where I forgot 
 to initialize to 0.
One big advantage of having everything default to 0 would be if the compiler was clever and used pre-cleared memory for arrays. That way you don't have to do any constructor work.
Aug 25 2022
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/24/2022 8:08 PM, Steven Schveighoffer wrote:
 NaN fails at that. It's silently swallowed by just about everything. Only when
a 
 human looks at some printout does it become obvious.
Seriously, *when* is 0 better than that? If you aren't looking at your output, then why are you calculating the value?
Aug 25 2022
next sibling parent kdevel <kdevel vogtner.de> writes:
On Thursday, 25 August 2022 at 16:39:14 UTC, Walter Bright wrote:
 [...]
 If you aren't looking at your output, then why are you 
 calculating the value?
To make decisions? double compute_pop () { double pop; // forgot to implement the computation // or ran into a nan by an instable computation pop = sqrt (-1.); pop += 0.; return pop; } int main () { auto pop = compute_pop (); if (pop < .5) writeln ("It will not rain."); else writeln ("It will rain."); return 0; }
Aug 25 2022
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/25/22 12:39 PM, Walter Bright wrote:
 On 8/24/2022 8:08 PM, Steven Schveighoffer wrote:
 NaN fails at that. It's silently swallowed by just about everything. 
 Only when a human looks at some printout does it become obvious.
Seriously, *when* is 0 better than that? If you aren't looking at your output, then why are you calculating the value?
Very few programs have a purpose to print an actual floating point number as text. Instead they are used for other things. Another example, let's say you are using a FP calculation to determine some sort of timing for bandwidth limiting. You might have something like: ```d if(val > maxBW) delaySending(); ``` If `val` or `maxBW` are NaN, this will always be a false condition (because of the wonderful property that comparisons with NaN are always false), so that code effectively never executes. Note that there's no `printf` here, and the code happily compiles and runs, it just does something unexepected. 0 is no better here *but also no worse*. -Steve
Aug 25 2022
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:
 0 is no better here *but also no worse*.
0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better. BTW, hex data doesn't have a NaN value. But a popular thing we'd do is initialize it to: 0xDEADBEEF which is pretty unlikely to occur in the wild. So when dumping hex data, and DEADBEEF is in there, you're very likely looking at uninitialized data getting into the output. I'd use it for both initializing malloc'd data before returning it to the caller, and setting free'd data to it. It was pretty effective at flushing out uninitialized allocated data, and use-after-free bugs. Using 0x00 was nowhere near as effective.
Aug 25 2022
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/25/22 9:01 PM, Walter Bright wrote:
 On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:
 0 is no better here *but also no worse*.
0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better.
I fully don't ever expect any changes to come from this discussion. But just to continue the point here, yes, it's slightly better in *some cases*. The question to answer is *how many cases*, and is the pain caused by having to go correct problems that should never have existed in the first place worth fixing those few cases where it actually helps. It's a matter of tradeoffs. There is no clear winner or loser, both have benefits and both have drawbacks. I've never encountered the benefits of NaN, so I'm biased towards initializing with 0.
 BTW, hex data doesn't have a NaN value. But a popular thing we'd do is 
 initialize it to:
 
    0xDEADBEEF
 
 which is pretty unlikely to occur in the wild. So when dumping hex data, 
 and DEADBEEF is in there, you're very likely looking at uninitialized 
 data getting into the output.
That's great. Now how do you find out where the problem starts? What if DEADBEEF is in your dump, but it's just memory that isn't being used yet? Is it still a problem? Note that this solves a mostly different problem -- using dangling pointers. This isn't about initialization. -Steve
Aug 26 2022
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/26/2022 9:28 AM, Steven Schveighoffer wrote:
 I fully don't ever expect any changes to come from this discussion.
True. I don't believe I've ever managed to change your mind!
 That's great. Now how do you find out where the problem starts?
The most important part is discovering that I *have* a problem. Next, I grep for DEADBEEF in the source code. And go from there. I am not making this up for the n.g. I have a *lot* of experience with it. I'm pointing out techniques that work. DEADBEEF turns a heisenbug into a reproducible bug. If it is reproducible, it is findable and fixable.
 What if DEADBEEF 
 is in your dump, but it's just memory that isn't being used yet? Is it still a 
 problem?
That depends on how you were using it.
 Note that this solves a mostly different problem -- using dangling pointers. 
 This isn't about initialization.
It is. The first use case I mentioned was initializing data returned from malloc to DEADBEEF. malloc returns uninitialized data, and I wanted to make sure it wasn't data that just happened to be 0 and "work", because therein lies heisenbugs and madness.
Aug 26 2022
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/26/22 11:30, Walter Bright wrote:

 It is. The first use case I mentioned was initializing data returned
 from malloc to DEADBEEF. malloc returns uninitialized data, and I wanted
 to make sure it wasn't data that just happened to be 0 and "work",
 because therein lies heisenbugs and madness.
Microsoft's C++ compiler used to do and probably still does that. Newly allocated memory and freed memory are initialized with specific patterns. (Optionally, I think with a compiler switch.) Ali
Aug 26 2022
parent reply IGotD- <nise nise.com> writes:
On Friday, 26 August 2022 at 18:53:33 UTC, Ali Çehreli wrote:
 Microsoft's C++ compiler used to do and probably still does 
 that. Newly allocated memory and freed memory are initialized 
 with specific patterns. (Optionally, I think with a compiler 
 switch.)

 Ali
I don't think it would do that in release mode. However, in debug there are several things going on with the VC C++ compiler. I haven't checked if it patterns malloc/free memory but it certainly patterns the stack memory and puts variables apart with guard patterns in between. Upon function/frame exit it checks all this. This is dog slow but very useful and I have found many bugs thanks to this. This of course will be unacceptable in a release build. Also initialize malloc/free with pattern would be undesirable in a release build.
Aug 26 2022
parent Paulo Pinto <pjmlp progtools.org> writes:
On Friday, 26 August 2022 at 20:37:40 UTC, IGotD- wrote:
 On Friday, 26 August 2022 at 18:53:33 UTC, Ali Çehreli wrote:
 Microsoft's C++ compiler used to do and probably still does 
 that. Newly allocated memory and freed memory are initialized 
 with specific patterns. (Optionally, I think with a compiler 
 switch.)

 Ali
I don't think it would do that in release mode. However, in debug there are several things going on with the VC C++ compiler. I haven't checked if it patterns malloc/free memory but it certainly patterns the stack memory and puts variables apart with guard patterns in between. Upon function/frame exit it checks all this. This is dog slow but very useful and I have found many bugs thanks to this. This of course will be unacceptable in a release build. Also initialize malloc/free with pattern would be undesirable in a release build.
Except Windows is actually compiled in release mode with local variables being initialized. https://msrc-blog.microsoft.com/2020/05/13/solving-uninitialized-stack-memory-on-windows/ And Android as well, https://source.android.com/docs/security/memory-safety/zero-initialized-memory?hl=en
Aug 27 2022
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 26.08.22 20:30, Walter Bright wrote:
 
 
 I am not making this up for the n.g. I have a *lot* of experience with 
 it. I'm pointing out techniques that work. DEADBEEF turns a heisenbug 
 into a reproducible bug. If it is reproducible, it is findable and fixable.
 
D's assert semantics may turn a reproducible bug into a heisenbug.
Aug 29 2022
parent reply Tejas <notrealemail gmail.com> writes:
On Tuesday, 30 August 2022 at 00:29:14 UTC, Timon Gehr wrote:
 On 26.08.22 20:30, Walter Bright wrote:
 
 
 I am not making this up for the n.g. I have a *lot* of 
 experience with it. I'm pointing out techniques that work. 
 DEADBEEF turns a heisenbug into a reproducible bug. If it is 
 reproducible, it is findable and fixable.
 
D's assert semantics may turn a reproducible bug into a heisenbug.
Uh, can you please elaborate on what you mean by this? How do `assert`s convert reproducible bugs into heisenbugs? I've never seen anyone say anything like this 😕
Aug 30 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 30 August 2022 at 11:48:26 UTC, Tejas wrote:
 How do `assert`s convert reproducible bugs into heisenbugs?
I pity the fool who uses -release.
Aug 30 2022
next sibling parent reply wjoe <invalid example.com> writes:
On Tuesday, 30 August 2022 at 11:55:29 UTC, Adam D Ruppe wrote:
 On Tuesday, 30 August 2022 at 11:48:26 UTC, Tejas wrote:
 How do `assert`s convert reproducible bugs into heisenbugs?
I pity the fool who uses -release.
Is this true for asserts w/o side effects?
Aug 30 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 30 August 2022 at 12:07:52 UTC, wjoe wrote:
 Is this true for asserts w/o side effects?
Yes. -release should seriously *never* be used for a lot of reasons, but read this part of the spec: https://dlang.org/spec/expression.html#assert_expressions
 1. The first AssignExpression must evaluate to true. If it does 
 not, an Assert Failure has occurred and the program enters an 
 Invalid State.
Notice that it doesn't say "must evaluate to true if actually evaluated", it just says must evaluate to true. If it would have failed, even if not actually compiled in, the program has *still* entered the Invalid State.
 8. Undefined Behavior: Once in an Invalid State the behavior of 
 the continuing execution of the program is undefined.
 Implementation Defined: Whether the first AssertExpression is 
 evaluated or not at runtime is typically set with a compiler 
 switch.
This combines to mean an optimizer is free to assume the asserts were all true as it moves forward which can get pretty random if it was never actually tested. I'm not sure if this is what Timon had in mind but it is its own thing to watch out for.
Aug 30 2022
parent wjoe <invalid example.com> writes:
On Tuesday, 30 August 2022 at 12:17:36 UTC, Adam D Ruppe wrote:
 On Tuesday, 30 August 2022 at 12:07:52 UTC, wjoe wrote:
 [...]
Yes. -release should seriously *never* be used for a lot of reasons, but read this part of the spec: https://dlang.org/spec/expression.html#assert_expressions
 [...]
Notice that it doesn't say "must evaluate to true if actually evaluated", it just says must evaluate to true. If it would have failed, even if not actually compiled in, the program has *still* entered the Invalid State.
 [...]
 [...]
This combines to mean an optimizer is free to assume the asserts were all true as it moves forward which can get pretty random if it was never actually tested. I'm not sure if this is what Timon had in mind but it is its own thing to watch out for.
That would make for a nice note in the spec :) Thanks for pointing this out.
Aug 30 2022
prev sibling next sibling parent reply bauss <jacobbauss gmail.com> writes:
On Tuesday, 30 August 2022 at 11:55:29 UTC, Adam D Ruppe wrote:
 On Tuesday, 30 August 2022 at 11:48:26 UTC, Tejas wrote:
 How do `assert`s convert reproducible bugs into heisenbugs?
I pity the fool who uses -release.
Arguably the only thing -release should ever have done is removing debug statements. Nothing more, nothing less.
Aug 30 2022
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/30/22 8:15 AM, bauss wrote:
 On Tuesday, 30 August 2022 at 11:55:29 UTC, Adam D Ruppe wrote:
 On Tuesday, 30 August 2022 at 11:48:26 UTC, Tejas wrote:
 How do `assert`s convert reproducible bugs into heisenbugs?
I pity the fool who uses -release.
Arguably the only thing -release should ever have done is removing debug statements. Nothing more, nothing less.
debug statements are not used by default. -Steve
Aug 30 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/30/2022 4:55 AM, Adam D Ruppe wrote:
 I pity the fool who uses -release.
-release is for people who do speed benchmarks. I speak from decades of experience.
Aug 30 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:
 -release is for people who do speed benchmarks.
The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".
Aug 30 2022
next sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Tuesday, 30 August 2022 at 16:16:38 UTC, Adam D Ruppe wrote:
 On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:
 -release is for people who do speed benchmarks.
The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".
-release says use me in terms of meaning, but masters says don't use it. I didn't know it had such dire consequences. This is an issue that affects contract programming. SDB 79
Aug 30 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/30/2022 9:25 AM, Salih Dincer wrote:
 On Tuesday, 30 August 2022 at 16:16:38 UTC, Adam D Ruppe wrote:
 On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:
 -release is for people who do speed benchmarks.
The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".
-release says use me in terms of meaning, but masters says don't use it. I didn't know it had such dire consequences. This is an issue that affects contract programming.
It's not dire. It's just necessary to understand what's happening. People who do speed benchmarks rarely do more than glance at the documentation, if that.
Aug 30 2022
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 31.08.22 00:08, Walter Bright wrote:
 On 8/30/2022 9:25 AM, Salih Dincer wrote:
 On Tuesday, 30 August 2022 at 16:16:38 UTC, Adam D Ruppe wrote:
 On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:
 -release is for people who do speed benchmarks.
The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".
-release says use me in terms of meaning, but masters says don't use it. I didn't know it had such dire consequences. This is an issue that affects contract programming.
It's not dire.
I think the term is fitting. Contracts are meant to support correctness, not to help exacerbate vulnerabilities.
 It's just necessary to understand what's happening.
People do not understand this. People barely understand undefined behavior. E.g., there were presentations at dconf where people were like: "we tested it [the piece of code with UB] and it worked, hence it is correct". A somewhat common use case is to disable contract/assert checking. Most people just assume that's what happens because introducing UB is not reasonable behavior.
 People who do speed benchmarks rarely do more than glance at the 
 documentation, if that.
 
People who don't know how to use the language usually write slow code anyway. (And it often computes only NaNs.)
Aug 30 2022
prev sibling parent "H. S. Teoh" <hsteoh qfbox.info> writes:
On Tue, Aug 30, 2022 at 04:16:38PM +0000, Adam D Ruppe via Digitalmars-d wrote:
 On Tuesday, 30 August 2022 at 15:50:48 UTC, Walter Bright wrote:
 -release is for people who do speed benchmarks.
The documentation should outright say then "never use this unless you are cheating on an artificial speed benchmark".
It should be renamed to -optimize-for-benchmark. ;-) T -- "A man's wife has more power over him than the state has." -- Ralph Emerson
Aug 30 2022
prev sibling parent reply cc <cc nevernet.com> writes:
On Friday, 26 August 2022 at 16:28:32 UTC, Steven Schveighoffer 
wrote:
 On 8/25/22 9:01 PM, Walter Bright wrote:
 On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:
 0 is no better here *but also no worse*.
0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better.
I fully don't ever expect any changes to come from this discussion. But just to continue the point here, yes, it's slightly better in *some cases*. The question to answer is *how many cases*, and is the pain caused by having to go correct problems that should never have existed in the first place worth fixing those few cases where it actually helps.
At the end of the day, the answer is: Default initializing floats to NaN is (very) arguably important to the niche high-expertise line of work Walter engaged in, and *fairly annoying* to the vast sea of untapped market potential and prospective programmers D may or may not sorta-kinda-hope to snag a share of someday, as its figurative hairline gradually recedes trying to determine how best to balance being the greatest wisest language in the world at certain arbitrary vanishingly minor daily debugging issues while still providing users with countless ways to freely shoot themselves in the foot and crash their planes on weekends. It's all a weighting issue, and the weight has been placed on the importance of the niche work over the some small percentage of grumbling and stubbed toes the different-from-how-everyone-else-does-it change incurs.
Oct 12 2023
parent reply Witold <witold.baryluk+dlang gmail.com> writes:
On Thursday, 12 October 2023 at 09:54:33 UTC, cc wrote:
 On Friday, 26 August 2022 at 16:28:32 UTC, Steven Schveighoffer 
 wrote:
 On 8/25/22 9:01 PM, Walter Bright wrote:
 On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:
 0 is no better here *but also no worse*.
0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better.
I fully don't ever expect any changes to come from this discussion. But just to continue the point here, yes, it's slightly better in *some cases*. The question to answer is *how many cases*, and is the pain caused by having to go correct problems that should never have existed in the first place worth fixing those few cases where it actually helps.
At the end of the day, the answer is: Default initializing floats to NaN is (very) arguably important to the niche high-expertise line of work Walter engaged in, and *fairly annoying* to the vast sea of untapped market potential and prospective programmers D may or may not sorta-kinda-hope to snag a share of someday, as its figurative hairline gradually recedes trying to determine how best to balance being the greatest wisest language in the world at certain arbitrary vanishingly minor daily debugging issues while still providing users with countless ways to freely shoot themselves in the foot and crash their planes on weekends. It's all a weighting issue, and the weight has been placed on the importance of the niche work over the some small percentage of grumbling and stubbed toes the different-from-how-everyone-else-does-it change incurs.
Niche maybe. Many other languages default initialize floats to 0 (i.e. Go). But NaN initialization on floats/double/complex did save me few times in the past, and allowed to actually be able to trace the problem, that I probably did not even knew I had otherwise. I like NaN initialization. Just like I like null initialization for pointers.
Oct 25 2023
parent mw <m g.c> writes:
On Thursday, 26 October 2023 at 02:42:37 UTC, Witold wrote:
 I like NaN initialization. Just like I like null initialization 
 for pointers.
Me too. Actually, I just tried the follwing in importC, to see how dmd will handle the init: ``` import_c.c #include <stdio.h> int main() { int i; double d; printf("%d %f\n", i, d); return 0; } ``` $ dmd import_c.c $ ./import_c 1973916528 0.000000 $ ./import_c 1108345712 0.000000 looks like it still using the C semantics. From what I read "How ImportC Works": https://dlang.org/spec/importc.html#internals " ... converts the C syntax into the same AST (Abstract Syntax Tree) that D uses". So, I'm just wondering can we add a switch: I really want the ImportC will init the variable with D's semantics. Walter, How does this sound? :-)
Oct 25 2023
prev sibling parent apz28 <home home.com> writes:
On Friday, 26 August 2022 at 01:01:24 UTC, Walter Bright wrote:
 On 8/25/2022 10:38 AM, Steven Schveighoffer wrote:
 0 is no better here *but also no worse*.
0 is equal or worse than NaN. It is true that sometimes 0 is equal. But it is *never* better. Using 0x00 was nowhere near as effective.
This seem be another string auto-decode problem to a basic type. It should implement similar to CheckedInt (as CheckedFloat?) for each case usage; not shoe horn into all use-cases
Aug 26 2022
prev sibling parent Dukc <ajieskola gmail.com> writes:
On Thursday, 25 August 2022 at 17:38:25 UTC, Steven Schveighoffer 
wrote:
 ```d
 if(val > maxBW) delaySending();
 ```

 If `val` or `maxBW` are NaN, this will always be a false 
 condition (because of the wonderful property that comparisons 
 with NaN are always false), so that code effectively never 
 executes. Note that there's no `printf` here, and the code 
 happily compiles and runs, it just does something unexepected.

 0 is no better here *but also no worse*.
In hindsight, the robust way to solve this would be that trying to compare NaN to anything would crash the program. No way to add that to D without too much breakage though, I'm afraid.
Aug 26 2022
prev sibling parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer 
wrote:
 A better option would be to throw an exception if NaN is used 
 in an operation.
How to kill a language, put exceptions everywhere, specially in math operations https://pspdfkit.com/blog/2020/performance-overhead-of-exceptions-in-cpp/ I hope you were joking
Aug 25 2022
next sibling parent reply bauss <jacobbauss gmail.com> writes:
On Friday, 26 August 2022 at 00:14:49 UTC, ryuukk_ wrote:
 On Thursday, 25 August 2022 at 03:08:54 UTC, Steven 
 Schveighoffer wrote:
 A better option would be to throw an exception if NaN is used 
 in an operation.
How to kill a language, put exceptions everywhere, specially in math operations https://pspdfkit.com/blog/2020/performance-overhead-of-exceptions-in-cpp/ I hope you were joking
That's why my response to it said it should be Error and not Exception, your program is effectively dead if you ever operate on NaN.
Aug 25 2022
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/25/2022 11:13 PM, bauss wrote:
 That's why my response to it said it should be Error and not Exception, your 
 program is effectively dead if you ever operate on NaN.
NaN has another use. If, say, your data collection is incomplete (like having a dead pixel in an array of sensors), giving that data point a NaN helps show what part of the results of the data analysis is dependent on the missing data.
Aug 26 2022
prev sibling next sibling parent IGotD- <nise nise.com> writes:
On Friday, 26 August 2022 at 00:14:49 UTC, ryuukk_ wrote:
 How to kill a language, put exceptions everywhere, specially in 
 math operations

 https://pspdfkit.com/blog/2020/performance-overhead-of-exceptions-in-cpp/

 I hope you were joking
I think what he's meaning is that a HW exception happens on NaN. Floating point exceptions will hardly be used anywhere and will kill the program if it happens. The good thing is that you know exactly the instruction that caused it.
Aug 26 2022
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/25/22 8:14 PM, ryuukk_ wrote:
 On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:
 A better option would be to throw an exception if NaN is used in an 
 operation.
How to kill a language, put exceptions everywhere, specially in math operations https://pspdfkit.com/blog/2020/performance-overhead-of-exceptions-in-cpp/ I hope you were joking
I'm not asking for this, I'm saying without having some sort of "fail upon use" mechanism (be it a signal or an exception), it's just not effective at finding initialization problems. What it has going for it over 0 is that it's definitively a problem *if you happen to see it*. But you have to look for it, and finding the source can be long gone by the time you see it. Think about null pointers -- they cost nothing but explode as soon as you try to use them. Exactly the correct mechanism, and it should happen close to where it was initialized. -Steve
Aug 26 2022
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/26/2022 9:22 AM, Steven Schveighoffer wrote:
 I'm not asking for this, I'm saying without having some sort of "fail upon
use" 
 mechanism (be it a signal or an exception), it's just not effective at finding 
 initialization problems. What it has going for it over 0 is that it's 
 definitively a problem *if you happen to see it*. But you have to look for it, 
 and finding the source can be long gone by the time you see it.
If you don't look for errors in the output, you are even less likely to find it with 0 initialization. I've also written here that there are legitimate uses of NaN where quitting upon use is undesirable. It's analogous to the "Replacement Char" in Unicode. We have experience with throwing an exception on seeing an invalid code point. It's the wrong answer. It's so wrong it's one of the motivators for Phobos version 2.
Aug 30 2022
parent jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 30 August 2022 at 15:55:27 UTC, Walter Bright wrote:
 [snip]
 I've also written here that there are legitimate uses of NaN 
 where quitting upon use is undesirable.

 [snip]
I feel like there aren't a lot of people here who do data analysis with missing data...NaNs all over the place...
Aug 30 2022