Movement against float.init being nan

Walter Bright newshound2 at digitalmars.com
Sat Aug 20 05:18:20 UTC 2022


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.


More information about the Digitalmars-d mailing list