August 19, 2012
On Sat, 18 Aug 2012 06:44:12 +0200
"Jesse Phillips" <jessekphillips+D@gmail.com> wrote:

> On Saturday, 18 August 2012 at 01:07:43 UTC, F i L wrote:
> > Your example:
> >
> >     float f;
> >     if (condition1)
> >         f = 7;
> >     ... code ...
> >     if (condition2)
> >         ++f;
> >
> > is flawed in that condition1 is _required_ to pass in sync with condition2, or you'll get a NaN in the result.
> 
> It is not flawed as that is exactly what he said condition1 did until the maintenance programmer made a change which caused this to no longer be in sync with condition2 (most likely fixing a bug as condition1 really should have been false).

If that's the case, then the code is far too damn fragile in the first place.

This:

    float f;
    if (condition1)
        f = 7;

Is bad fucking code, period. I'd expect *ANY* usage of f after that (except, of course, a plain assignment to it) to be flagged as an error. That's because *even if* f isn't technically used without assignment, it still indicates that somebody didn't think their shit through and may already be hiding a bug (in which case they're damnned lucky it's a float instead of an int) - and even if not, then it's still too damn fragile anyway and *will* likely wind up creating a bug once someone goes and touches that code.

FWIW, Last time we debated this on the NG, this was the point where Walter got stuck on the irrelevant "But it's not garbage-inited like C!" strawman. I hope we can do better this time.

August 19, 2012
On 8/18/2012 7:36 PM, Nick Sabalausky wrote:
> If that's the case, then the code is far too damn fragile in the first
> place.
>
> This:
>
>      float f;
>      if (condition1)
>          f = 7;
>
> Is bad fucking code, period. I'd expect *ANY* usage of f after that
> (except, of course, a plain assignment to it) to be flagged as an
> error. That's because *even if* f isn't technically used without
> assignment, it still indicates that somebody didn't think their shit
> through and may already be hiding a bug (in which case they're damnned
> lucky it's a float instead of an int) - and even if not, then it's
> still too damn fragile anyway and *will* likely wind up creating a bug
> once someone goes and touches that code.
>
> FWIW, Last time we debated this on the NG, this was the point where
> Walter got stuck on the irrelevant "But it's not garbage-inited like C!"
> strawman. I hope we can do better this time.

With respect, I think that you are conflating two different questions.

If the question is, "should static checking reject this code as flawed?", then NaN is irrelevant, and a strawman, yes.

But if the question is, "is default-initializing to NaN better than default-initializing to garbage?", then it's entirely on point. (And that is the topic of this thread.)

Yes, it would be great if the D compiler (or a C++11 compiler, or C# or Scala or what have you) could do a complete static check of the code. As a practical matter, today's compiler technology cannot. (And if it could, you'd get complaints about compile times... <grin/>)

Since the flaw may not be detected statically at compile time, it's nice to know that NaN will detect it at runtime (in the same sense that a minefield "detects" an intruder).

Consider how useful *integer* NaN is. Oh, you didn't realize that, when you used zero, or minus one, or 0xFFFF or its moral equivalents, to flag an error or exceptional condition on a function that returns what is normally a number, that you were hand-rolling an integer NaN? For that matter, wouldn't it be nice to have a Boolean NaN? (not "true", not "false", but "not yet decided")

Except of course that zero, and one, and minus one, and all-bits-set are all extremely common and useful *arithmetic* values, and all too likely to be returned legitimately. So having a hardware NaN in floating point, particularly one that "taints" all future results it participates in, and further one that can (by definition) never be a legitimate number, is genius. And having Walter design D to take advantage of it is... well, perhaps not genius, but damned smart.

I'll build my bricks with Walter's straw, any day.



August 19, 2012
OT:

On Sunday, 19 August 2012 at 03:16:39 UTC, Davidson Corry wrote:
> For that matter, wouldn't it be nice to have a Boolean NaN? (not "true", not "false", but "not yet decided")

enum BOOL {
   TRUE,
   FALSE,
   FILE_NOT_FOUND
}

http://thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx
August 19, 2012
On 8/18/2012 2:16 PM, bearophile wrote:
> Another sub-thread that shows a very important thing, that's missing:
>
> http://www.reddit.com/r/programming/comments/yehz4/nans_just_dont_get_no_respect/c5v1u0y

Oh come on. That's called a "user defined type."

struct OptionType {
    private T m_value;

    @property T value() { check m_value; return m_value; }
}
August 19, 2012
On 8/18/2012 7:27 PM, Nick Sabalausky wrote:
> Bullshit, I've used C# which does exactly what Walter is arguing
> against, and the result never involved getting annoyed and blindly
> tossing in an "=0".

I've seen this problem in the real world, even though you don't make such mistakes.


August 19, 2012
On 8/18/2012 8:31 PM, Adam D. Ruppe wrote:
> enum BOOL {
>     TRUE,
>     FALSE,
>     FILE_NOT_FOUND
> }

I used to work with digital electronics. There, "boolean" logic actually had 4 states:

    True
    False
    Don't Know
    Don't Care

August 19, 2012
On Sat, 18 Aug 2012 20:16:37 -0700
Davidson Corry <davidsoncorry@comcast.net> wrote:

> On 8/18/2012 7:36 PM, Nick Sabalausky wrote:
> > If that's the case, then the code is far too damn fragile in the first place.
> >
> > This:
> >
> >      float f;
> >      if (condition1)
> >          f = 7;
> >
> > Is bad fucking code, period. I'd expect *ANY* usage of f after that (except, of course, a plain assignment to it) to be flagged as an error. That's because *even if* f isn't technically used without assignment, it still indicates that somebody didn't think their shit through and may already be hiding a bug (in which case they're damnned lucky it's a float instead of an int) - and even if not, then it's still too damn fragile anyway and *will* likely wind up creating a bug once someone goes and touches that code.
> >
> > FWIW, Last time we debated this on the NG, this was the point where Walter got stuck on the irrelevant "But it's not garbage-inited like C!" strawman. I hope we can do better this time.
> 
> With respect, I think that you are conflating two different questions.
> 
> If the question is, "should static checking reject this code as flawed?", then NaN is irrelevant, and a strawman, yes.
> 
> But if the question is, "is default-initializing to NaN better than default-initializing to garbage?", then it's entirely on point. (And that is the topic of this thread.)
> 

No offense taken (or intended), but I think you're conflating the different branches of the discussion.

The "NaN-initing better than garbage/zero-initing" was a key
point of the OP, yes, but not of all branches of discussion, and not
the only point in the article either.

Please reread the thread and notice that the branch I was replying to was directed specifically at this section of the article:

--------------------------------------
Given the code:

    float f;
    if (condition)
        ++f;

the user writes "in language X, the compiler complains on line 3 saying that f is used without being initialized. Isn't that a better solution?" For that example, it probably is a better solution. But consider:

    float f;
    if (condition1)
        f = 7;
    ... code ...
    if (condition2)
        ++f;

[Goes on attempting to build a case against the static checking]
--------------------------------------

So yes, the OP *IS* claiming "NaN-initing > conservative static checks" and that is what this branch of the thread, including the post I directly replied to, was directly addressing.


> Yes, it would be great if the D compiler (or a C++11 compiler, or C# or Scala or what have you) could do a complete static check of the code. As a practical matter, today's compiler technology cannot. (And if it could, you'd get complaints about compile times... <grin/>)
> 

Actually, I disagree. I want a static check, but I *don't* want it to be complete. Largely because of the difficulty of doing so and the compile times, yes, BUT also because (as I already said) code such as this:

    float f;
    if (condition)
        ++f;
    // Complex stuff that may involve f in certain codepaths

Is *already* fragile and bad, and could easily hide/generate bugs even with NaN. In fact, there's a reasonable chance it may already be a bug, again even with NaN. And even with NaN, it would still be much better to just get an error for the whole damn thing: "ERROR: This is screwy fucking code. Even if it's not technically buggy right now, which is questionable anyway, it can easily become a bug if it gets altered without being very, VERY careful. So go back and rewrite it to not be so damned fragile."


> Since the flaw may not be detected statically at compile time, it's nice to know that NaN will detect it at runtime (in the same sense that a minefield "detects" an intruder).
> 

I'm advocating conservative static checking. It WILL be detected at compile-time (along with some false positives, but I've been arguing these are GOOD false positives, or *at least* perfectly acceptable).

> Consider how useful *integer* NaN is. Oh, you didn't realize that,

Please don't put words in my mouth. I've advocated in past discussions
for making 'int.init' be 0xDEADBEEF or 0x69696969 as a
"next-best thing" for when (as with D) static checking isn't performed.

> when you used zero, or minus one, or 0xFFFF or its moral equivalents, to flag an error or exceptional condition on a function that returns what is normally a number, that you were hand-rolling an integer NaN? For that matter, wouldn't it be nice to have a Boolean NaN? (not "true", not "false", but "not yet decided")
> 
> Except of course that zero, and one, and minus one, and all-bits-set are all extremely common and useful *arithmetic* values, and all too likely to be returned legitimately. So having a hardware NaN in floating point, particularly one that "taints" all future results it participates in, and further one that can (by definition) never be a legitimate number, is genius. And having Walter design D to take advantage of it is... well, perhaps not genius, but damned smart.
> 

Right. But what's *even smarter* than that, is just eliminating the whole f***** problem at compile-time. Walter has specifically argued against the wisdom of that on various occasions (including in this article), and what I'm saying is that I don't buy *that* reasoning or its conclusion. (And then I went on and bitched about a previous discussion where he kept trying to use "NaN/0-init > garbage-init" as a rebuttal to my completely *different* argument of "static checks > NaN/0-init". Hence the "strawman".)


August 19, 2012
On Friday, August 17, 2012 17:03:13 Walter Bright wrote:
> Our discussion on this in the last few days inspired me to write a blog post about it:
> 
> http://www.reddit.com/r/programming/comments/yehz4/nans_just_dont_get_no_res pect/
> 
> http://www.drdobbs.com/cpp/nans-just-dont-get-no-respect/240005723

FWIW, I'm very surprised by how negatively many programmers seem to react to NaN. I think that how D handles it is great. IMHO, if anything, it's the fact that we don't have something similar for integral values which is problematic, not the fact that floating point values default initialize to NaN.

- Jonathan M Davis
August 19, 2012
On Sat, 18 Aug 2012 20:44:52 -0700
Walter Bright <newshound2@digitalmars.com> wrote:

> On 8/18/2012 7:27 PM, Nick Sabalausky wrote:
> > Bullshit, I've used C# which does exactly what Walter is arguing against, and the result never involved getting annoyed and blindly tossing in an "=0".
> 
> I've seen this problem in the real world, even though you don't make such mistakes.
> 

I've seen lots of stupid shit in production code. I've seen a data-loading function named "save". So which foot should we shoot off in our fear of that real-world mistake?

And yes, yes, yes, I know AND AGREE that designing a language to help prevent mistakes is the right things to do, but I strongly believe you've gotten it backwards in this specific case (nothing personal, of course). I think you're:

1. Severely overstating the problem of "blindly toss in a =0"

2. Undervaluing the benefit of C#-style static checks for possibly-initited value usage.

After actually *using* both D (default-initialization) and C# (statically/conservatively ensure things can't be accessed without being explicitly inited), and I'm convinced the benefits of the static checks easily outweigh the fear of a knee-jerk "=0".

August 19, 2012
On Sat, 18 Aug 2012 20:52:01 -0700
Walter Bright <newshound2@digitalmars.com> wrote:

> On 8/18/2012 8:31 PM, Adam D. Ruppe wrote:
> > enum BOOL {
> >     TRUE,
> >     FALSE,
> >     FILE_NOT_FOUND
> > }

Heh, that's probably the #1 classic Daily WTF :)

> 
> I used to work with digital electronics. There, "boolean" logic actually had 4 states:
> 
>      True
>      False
>      Don't Know
>      Don't Care
> 

It sounds like it's some EE joke, but yea, strange as it seems, not only is there really a "Don't care", but it's actually useful (for not wasting excess silicon/logic-gates on states that can't (or shouldn't) ever occur - it means "ehh, just make this whatever value would require the fewest logic gates since it won't actually matter anyway").

I only ever dabbled with some very rudimentary digital EE, I'm still a bit of a novice, but it's pretty damn cool stuff.