| |
| Posted by Walter Bright in reply to Steven Schveighoffer | PermalinkReply |
|
Walter Bright
| 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.
|