www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - NaNs Just Don't Get No Respect

reply Walter Bright <newshound2 digitalmars.com> writes:
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_respect/

http://www.drdobbs.com/cpp/nans-just-dont-get-no-respect/240005723
Aug 17 2012
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Walter Bright:

 http://www.drdobbs.com/cpp/nans-just-dont-get-no-respect/240005723

You have omitted the detail that double.nan !is double.init. On a more general note, I know many professionals in other fields that never write small articles about what they are doing. So is it normal just for programmers to write (small) articles like this? I write them, and other programmers I know write similar things. Maybe to program you need (among other things) active linguistic centers in the brain :-) Bye, bearophile
Aug 17 2012
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/17/2012 8:03 PM, bearophile wrote:
 Why aren't my friends that work or study chemistry writing free small online
 articles like my programmer&CS friends do?

I have no idea. Please ask them and report back.
Aug 17 2012
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/18/2012 6:51 AM, Peter Alexander wrote:
 Maybe it's related to the tendency for programmers to be libertarians, which
 would also explain the whole open source software movement. They want to share
 knowledge freely, and online articles would be part of that.

I find this peculiar, as the open source software movement is frequently associated with communism, not libertarianism. (Although I do think it is much more correct to associate it with libertarianism.)
 This reason likely
 explains this particular article: there was disagreement on the use of NaNs for
 initialisation, so Walter wanted to express his take on the matter to the
 masses. I have done similar things in the past, e.g. blogging about my thoughts
 on immutable in D.

I write the blogs in Dr. Dobbs because the editors of DDJ have always been very nice to me and supportive of my efforts, going all the way back to my Zortech days. They asked me to write the blogs, and send me nice comments about them. The positive responses they get on reddit encourage me to continue doing them. I wrote the NaN one because there was a lot of interesting discussion on it in the n.g., and so I thought a wider audience would find it interesting as well.
Aug 18 2012
prev sibling parent Don Clugston <dac nospam.com> writes:
On 18/08/12 05:03, bearophile wrote:
 F i L:

 Why would it matter what is "normal"?

It matters to me because I am curious. Why aren't my friends that work or study chemistry writing free small online articles like my programmer&CS friends do? Maybe it's systematic differences in their brain brain? Or it's just more easy to talk about coding compared to botany and chemistry and making engines? Or maybe programmers don't know what they are doing? Or maybe it's just I am not looking in the right places? :-) Bye, bearophile

They write journal articles instead. Producing journal articles have never been of major importance for IT, but they are crucial for science. And if it isn't a new, publishable result, you're more likely to contribute to something like Wikipedia, than to write a blog post. OTOH some people do blog, for example, http://terrytao.wordpress.com/ who is one of the top mathematicians on the planet.
Aug 20 2012
prev sibling next sibling parent reply "F i L" <witte2008 gmail.com> writes:
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. In this scenario, 
you're forced to provide a usable default explicitly no matter 
what, so your later argument:

 "This leads to the programmer getting annoyed with false 
 positive error diagnostics, and he'll likely add an =0"

doesn't make sense, because he needs to provide a usable value in the first place. This is exactly why I was arguing that explicit assignment to NaN was better for debugging as well. Because a maintenance programmer, that steps in at a later date, would: 1. be less likely to change an explicit assignment to NaN without understand the code fully first. 2. have an easier time tracking down the origin of a NaN error, because variables not explicitly assigned to NaN _can't_ be the culprit. Imagine we have code that looks like: class SomeClass { float foo; float bobDole; float someKind; float barFoo = float.nan; float aVariable; float barBaz; this() { ... lotsa init code ... } } If floats defaulted to 0.0f, then we'd know exactly which variable to analyze in order to find the source of our NaN bug: 'barFoo'. Since we don't have this visual clue, we have to analyze all of them. Of course, we can reverse this by explicitly assigning all, except 'barFoo', to 0.0f, but that's: 1. less convenient to type 2. harder to visually parse to find the potential NaNs 3. inconsistent with 'int' This is how I wish D worked: 1. Functions: void foo() { float f; f ++; // compiler error } void foo() { float f; if (condition1) f = 5; if (condition2) f ++; // compiler error } 2. Structs & Classes: class Foo { float f; // 0.0f void bar() { f++; } // Notice: no constructor defined } void main() { auto foo = new Foo(); foo.bar(); // works fine } Unfortunately, structs don't have default constructors in D. I'm not sure exactly why that is, but if there's some design or performance issue, structs could always work like this instead: 3. Structs: struct Foo { float f; // compiler error } struct Foo { float f = 0; // OK } struct Foo { float f; // OK, if: this() { f = 0; } // set in constructor }
Aug 17 2012
next sibling parent reply Davidson Corry <davidsoncorry comcast.net> writes:
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.
Aug 18 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
Aug 18 2012
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/18/2012 9:33 PM, Nick Sabalausky wrote:
 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

Yup, it turns out that all 4 states are very useful.
Aug 18 2012
prev sibling parent Davidson Corry <davidsoncorry comcast.net> writes:
On 8/18/2012 9:05 PM, Nick Sabalausky wrote:

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

I'm glad. And it's entirely likely that I missed something. I didn't read the whole thread, I was just replying to your one message. Lazy...
 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.

Fair enough. I agree with you that the claim is in error -- not because I think the > operator should be pointing <, but because the two things are unrelated and shouldn't be compared. One is a compile-time check, the other a runtime minefield. One is a logic analysis, the other an out-of-domain value test. They are not XOR -- *both* should be used. (And some of us clever programmers will slip bogus programs past both of them anyway...)
 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...

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."

So true. But the only technology I have found to date capable of such insight is a good code review. And a good reviewer who is willing to take the time and analyze my code in depth (and then patiently and politely get past my mule-headed stubbornness and get me to see what he's saying) is a treasure beyond price. Man, if you can package *that* in a compiler, I'm buyin'!
 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.

I apologize. I did not mean that *you personally* were advocating specific "not an integer" values like -1. I meant the generic "you" as in many APIs that I am sure you are familiar with. Certainly there may be applications where a human-recognizable "dead beef" flag works well... and others where you don't want to drop a "not a value" value into the middle of a useful range. (0xDEADBEEF is not a useful value, but 0xDEADBEEE and 0xDEADBEF0 are??) What I was trying to say was that programmers re-invent the "not a valid value" trick all the time. For example, the Unicode Consortium defines the code point 0xFFFE to be an invalid character, and thus allows tricks like the Byte Order Mark. In my own specialty of Windows installer work, a zero exit code marks "success" and a non-zero exit is "failure"... except that the special values of decimal 3010 and (archaically) 8192 flag "success but reboot required to complete the install". NULL and nullptr are special values for C/C++. And so on. I have needed a flag to indicate a Boolean with a one-time initialization often enough to have written a small class to encapsulate the True|False|NotYetSet behavior. And it lacks rigor. For instance, it does not have the "taints all downstream expressions" behavior that floating NaN does. One of these days I will rewrite it correctly and add it to a library.
 ...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 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".)

OK. Well, you may need to write your own compiler, then. You and Walter may be enlightened enough to gain insight through earnest reason together. Me, you usually have to hit me over the head with something heavy a couple of times before I get your point. <grin> Ouch. -- Davidson
Aug 20 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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.
Aug 18 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/18/2012 9:21 PM, Nick Sabalausky wrote:
 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".

I'm less willing to throw default initialization out - I like it & rely on it. The C# approach pretty much ends default initialization, including for user defined types.
Aug 18 2012
parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2012-08-19 05:54:49 +0000, Walter Bright <newshound2 digitalmars.com> said:

 On 8/18/2012 9:21 PM, Nick Sabalausky wrote:
 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".

I'm less willing to throw default initialization out - I like it & rely on it. The C# approach pretty much ends default initialization, including for user defined types.

I like default initialization too, and I rely on it. By that I mean that all the time I write "size_t count;" and assume it'll be default initialized to zero. I like it because it's less typing and it's simple: if I don't assign anything it's zero. I can't do that for floats or chars, because the default initialization gives me a unusable value. In my mind C#-style conservative flow analysis errors are better than default initialization to a bogus value because they catch the problem at compile time. But on the other side I'd rather not give up on integer default initialization to zero, as I actually prefer this over everything else. So Walter, which default initialization do you like an rely on? As I said, personally, I'd have everything initialized to zero by default. But at this point you can't really change this even if you want to: some program somewhere might rely on float being initialized to NaN by default and might start to give erroneous results if you change the default. (Notice the irony?) -- Michel Fortin michel.fortin michelf.ca http://michelf.ca/
Aug 19 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/19/2012 8:18 AM, Peter Alexander wrote:
 Personally, I'd prefer option 1. Walter's argument is that this "leads to the
 programmer getting annoyed with false positive error diagnostics, and he'll
 likely add an =0", which is true, but in my opinion this scenario is quite rare
 to start with, and it's even more rare that 0 isn't actually the right
 initialisation value, and even then it's only a problem if the introduced bug
is
 hard to reproduce.

Rare, yes, it's rare. But it's really ugly and hard to find when it does happen.
 I find it more likely that the NaN will go unnoticed and
 cause rare bugs.

NaNs in your output are pretty obvious. For example, if your accounting program prints "NAN" for the amount on the payroll cheques, someone is guaranteed to notice. But if it's a few cents off in your disfavor, it might take you years to discover there's a problem. Critical systems also would find a NaN command a lot easier to detect than an off-by-two command, and would be able to shut down and engage the backup.
Aug 19 2012
parent Don Clugston <dac nospam.com> writes:
On 20/08/12 22:21, cal wrote:
 On Monday, 20 August 2012 at 19:28:33 UTC, Peter Alexander wrote:
 On Sunday, 19 August 2012 at 22:22:28 UTC, Walter Bright wrote:
 I find it more likely that the NaN will go unnoticed and
 cause rare bugs.

NaNs in your output are pretty obvious. For example, if your accounting program prints "NAN" for the amount on the payroll cheques, someone is guaranteed to notice. But if it's a few cents off in your disfavor, it might take you years to discover there's a problem. Critical systems also would find a NaN command a lot easier to detect than an off-by-two command, and would be able to shut down and engage the backup.

The problem is that it's easy for even NaN's to be filtered out. float x = 0.0f; float y; // oops float z = min(x, y); // NaN has disappeared, unnoticed! My argument is that conservative compile time errors on uninitialised variables are more likely to catch these errors.

I just tried this: float a, b = 10; writeln(min(a, b), ", ", fmin(a, b)); Result: nan, 10 I think that is incorrect - both should give NaN. The scientific viz software I use at work returns NaN for any numerical operation on NaN values, means, smoothing, etc.

No, it's the other way around. The IEEE 754 standard defines min(x, NaN) == min(NaN, x) == x. According to the C standard, fmin() should be returning 10, as well. There is a bug in fmin(). However min() and max() are extremely unusual in this respect. Almost everything else involving a NaN returns NaN.
Aug 21 2012
prev sibling next sibling parent "F i L" <witte2008 gmail.com> writes:
bearophile wrote:
 On a more general note, I know many professionals in other 
 fields that never write small articles about what they are 
 doing. So is it normal just for programmers to write (small) 
 articles like this? I write them, and other programmers I know 
 write similar things. Maybe to program you need (among other 
 things) active linguistic centers in the brain :-)

Why would it matter what is "normal"? Normality is constantly changing anyways. Or are you just curios if it's been common practice in the past?
Aug 17 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
F i L:

 Why would it matter what is "normal"?

It matters to me because I am curious. Why aren't my friends that work or study chemistry writing free small online articles like my programmer&CS friends do? Maybe it's systematic differences in their brain brain? Or it's just more easy to talk about coding compared to botany and chemistry and making engines? Or maybe programmers don't know what they are doing? Or maybe it's just I am not looking in the right places? :-) Bye, bearophile
Aug 17 2012
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
I remember you (Walter) or somebody else talking about signaling 
NaNs before, but I don't remember many details about it. Does D 
use them? Is this an answer to the Reddit commenter who mentioned 
immediately throwing an exception?
Aug 17 2012
prev sibling next sibling parent "Jesse Phillips" <jessekphillips+D gmail.com> writes:
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).
Aug 17 2012
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/17/2012 5:03 PM, 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_respect/

 http://www.drdobbs.com/cpp/nans-just-dont-get-no-respect/240005723

http://news.ycombinator.com/item?id=4399635
Aug 17 2012
prev sibling next sibling parent "Bernard Helyer" <b.helyer gmail.com> writes:
On Saturday, 18 August 2012 at 05:07:19 UTC, Walter Bright wrote:
 On 8/17/2012 8:03 PM, bearophile wrote:
 Why aren't my friends that work or study chemistry writing 
 free small online
 articles like my programmer&CS friends do?

I have no idea. Please ask them and report back.

"When a non-programmer hears about Michael’s articles the source code I have released, I usually get a stunned “WTF would you do that for???” look. They don’t get it. Programming is not a zero-sum game. Teaching something to a fellow pro- grammer doesn’t take it away from you. I’m happy to share I can, because I’m in it for thelove of programming. The Ferraris are just gravy, honest!" -John Carmack --- I enjoyed ze article very much.
Aug 18 2012
prev sibling next sibling parent "F i L" <witte2008 gmail.com> writes:
On Saturday, 18 August 2012 at 04:44:16 UTC, Jesse Phillips 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).

It's flawed because condition2 relies upon condition1 to function without error. The example, as Walter presented it, is logically describing: float f; if (condition1) { f = 7; if (condition2) f ++; } because the only way Walter's next argument, that "a programmer will haphazardly supply a default value where there _should_ be a NaN", is in error, because if condition2 _does_ rely upon condition1, then there _shouldn't_ be a NaN by the time condition2 is reached, as condition2 _should_ be nested (like above), and the programmer made a logical mistake (which the compiler can warn him about). Remember, NaN in this example is only used as error checking to ensure 'f' is assigned before it's manipulated. If however, condition2 isn't intended to rely upon condition1, then 'f' needs to be explicitly assigned a usable value before condition2, and outside of condition1. Which also negates Walter's "haphazardly assigned" argument, because 'f' _isn't_ intended to be NaN (so assigning to 0.0f makes sense), and condition1 is the only place 'f' is assigned in the example. The only way code like Walter's example is written, is when the coder has made a logical mistake. Which, again, the compiler can warn us about: float f; if (condition1) f = 7; // f _could_ be unassigned, therefor... if (condition2) f ++; // ...should be error Furthermore, in a situation where the value _is_ intended to be NaN (for example, to check 'f' for NaN after condition2) then an explicit assignment to NaN will help document that intent, and help keep a third party from mistakenly assigning it to something else at a later date: float f = float.nan; if (condition1) f = 7; if (condition2) f ++; ...lotsa code... if (f == float.nan) doSomething(); else doSomethingElse(); In this situation, if floats default to NaN and 'f' wasn't explicitly defined, a maintenance programmer might not recognize the last condition, think "gee, I need to set that to a value in case condition1 fails when condition2 does not", and mistakenly assign 'f' a usable value, thus introducing a silent bug.
Aug 18 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
F i L:

 It's flawed because condition2 relies upon condition1 to

Some people suggest: http://www.reddit.com/r/programming/comments/yehz4/nans_just_dont_get_no_respect/c5uzt46 Regarding that Reddit thread in general, most people there seem quite ignorant about NaNs, so this little article was a small improvement. Bye, bearophile
Aug 18 2012
prev sibling next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Saturday, 18 August 2012 at 03:03:23 UTC, bearophile wrote:
 Why aren't my friends that work or study chemistry writing free 
 small online articles like my programmer&CS friends do? Maybe 
 it's systematic differences in their brain brain? Or it's just 
 more easy to talk about coding compared to botany and chemistry 
 and making engines? Or maybe programmers don't know what they 
 are doing? Or maybe it's just I am not looking in the right 
 places? :-)

I'd also like to know this. Maybe it's just the size of the audience. There's a very large community of programmers online, but the community of chemists and botanists is not so large, so there's less reason to share online. Maybe it's because programming is so accessible, allowing younger, more opinionated people to share their thoughts. It's easy to achieve something in programming: just download a compiler/interpreter, follow some online tutorials and you'll have something worth sharing. In Chemistry on the other hand, you really need to go to university before you can start doing something beyond simple experiments with household ingredients. Maybe it's a delusion of grandeur. A lot of programmers have the idea that they could program up the next big computer game, or make the next Facebook or Twitter. When they inevitably fail, they turn to blogging ("Those who can't, teach"). I've noticed this especially on HackerNews, which is of course filled with people with such delusions. P.S. before anyone gets offended, I'm not suggesting this applies to all programming bloggers! Maybe it's related to the tendency for programmers to be libertarians, which would also explain the whole open source software movement. They want to share knowledge freely, and online articles would be part of that. Maybe it's related to the religion thing. Programmers tend to be religious about their languages and practices, and are often challenged on their beliefs, so they'll tend to want to preach their ideas to the masses. This reason likely explains this particular article: there was disagreement on the use of NaNs for initialisation, so Walter wanted to express his take on the matter to the masses. I have done similar things in the past, e.g. blogging about my thoughts on immutable in D. Maybe it's all those things plus more. That's my thoughts anyway.
Aug 18 2012
prev sibling next sibling parent "Jesse Phillips" <jessekphillips+D gmail.com> writes:
On Saturday, 18 August 2012 at 09:32:01 UTC, F i L wrote:

 It's flawed because condition2 relies upon condition1 to 
 function without error. The example, as Walter presented it, is 
 logically describing:

     float f;
     if (condition1) {
         f = 7;
         if (condition2)
             f ++;
     }

This greatly changes the semantics of the code. I do not disagree that the example indicates the original programmer is likely wrong and needs to improve the description of his intent. What I disagree on is that it is that complaining that f might not be initialized will force the programmer to think and address the true issue. It is also taking the example at face value. The complexity of the relationship could be harder too see (I don't know what that would be), and somewhere else where condition1 is set there could be code: auto condition1 = getmevalue(); enforce(condition1 && condition2, "Huston this is the problem!"); Someone is probably at fault and the one addressing the issue may still get it wrong; if it is the second programmer hopefully they will have more information about what they need as they were the ones changing the semantics of the code.
Aug 18 2012
prev sibling next sibling parent "F i L" <witte2008 gmail.com> writes:
On Saturday, 18 August 2012 at 14:29:12 UTC, Jesse Phillips wrote:
 On Saturday, 18 August 2012 at 09:32:01 UTC, F i L wrote:

 It's flawed because condition2 relies upon condition1 to 
 function without error. The example, as Walter presented it, 
 is logically describing:

    float f;
    if (condition1) {
        f = 7;
        if (condition2)
            f ++;
    }

This greatly changes the semantics of the code. I do not disagree that the example indicates the original programmer is likely wrong and needs to improve the description of his intent.

I agree, and that's my point here. The original example is an erroneous presupposition that leads to faulty conclusions. If the compiler warned against this error the programmer would likely fix the code to a state which prevents the potential bug this example was originally intended to illustrate.
 What I disagree on is that it is that complaining that f might 
 not be initialized will force the programmer to think and 
 address the true issue. It is also taking the example at face 
 value. The complexity of the relationship could be harder too 
 see (I don't know what that would be),

I too, don't know of any examples where defaulting to NaN would prevent an error where static analysis would not, though I'm always open to argument. Given the benefits of static analysis and defaulting to 0.0f for class members (which I listed in previous posts), I see that position as the one with demonstrable benefit.
 and somewhere else where condition1 is set there could be code:

 auto condition1 = getmevalue();
 enforce(condition1 && condition2, "Huston this is the 
 problem!");

I don't see how this changes the situation with NaN vs. static analysis.
Aug 18 2012
prev sibling next sibling parent "Jesse Phillips" <jessekphillips+D gmail.com> writes:
On Saturday, 18 August 2012 at 18:06:12 UTC, F i L wrote:
 If the compiler warned against this error the programmer would 
 likely fix the code to a state which prevents the potential bug 
 this example was originally intended to illustrate.

It is this statement that indicates you didn't fully comprehend what was written in the article. It is likely that the author will initialize f to a value. In which case you have increased the likelyhood that the incorrect value of 0 will be assigned instead of NAN. So I do not agree that it is likely he will fix the code in a manner that would prevent this bug from happening.
Aug 18 2012
prev sibling next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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

Bye,
bearophile
Aug 18 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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; } }
Aug 18 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/19/2012 5:08 AM, bearophile wrote:
 With a different type system the compiler makes sure at compile-time that x is
 not empty (this means the compiler makes sure in no code paths x is used before
 testing it contains something), avoiding the run-time exception.

That's called disabling the default constructor with disable.
Aug 19 2012
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/19/2012 2:41 PM, Simen Kjaeraas wrote:
 Nullable!int a;

 int x = a; // Compile-time error: a might be null!

 if ( a ) {
     int y = a; // 's fine, we know it's not null.
 }

You'd want the int to be the non-nullable type. You can do this with D's type system. Each state would be a different type, with user defined conversions between them.
Aug 19 2012
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/17/12 8:03 PM, 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_respect/

Homerun. Nice!! Andrei
Aug 18 2012
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sat, 18 Aug 2012 23:12:10 +0200
"Jesse Phillips" <jessekphillips+D gmail.com> wrote:

 On Saturday, 18 August 2012 at 18:06:12 UTC, F i L wrote:
 If the compiler warned against this error the programmer would 
 likely fix the code to a state which prevents the potential bug 
 this example was originally intended to illustrate.

It is this statement that indicates you didn't fully comprehend what was written in the article. It is likely that the author will initialize f to a value. In which case you have increased the likelyhood that the incorrect value of 0 will be assigned instead of NAN. So I do not agree that it is likely he will fix the code in a manner that would prevent this bug from happening.

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".
Aug 18 2012
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
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.
Aug 18 2012
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
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
Aug 18 2012
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
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".)
Aug 18 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
Aug 18 2012
parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 19.08.2012 06:12, schrieb Jonathan M Davis:
 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.

i think many of these programmers seems to think that D is introducing this NaN-Type ...
Aug 18 2012
next sibling parent reply Sean Cavanaugh <WorksOnMyMachine gmail.com> writes:
On 8/19/2012 12:12 AM, dennis luehring wrote:
 Am 19.08.2012 06:12, schrieb Jonathan M Davis:
 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.

i think many of these programmers seems to think that D is introducing this NaN-Type ...

Nobody knows how floats work, without being locked in a closet for a at least a week and told to change their doubles back into floats and fix their code, since thats where 99% of precision problems actually come from.
Aug 18 2012
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/18/2012 11:21 PM, Sean Cavanaugh wrote:
 Nobody knows how floats work, without being locked in a closet for a at least a
 week and told to change their doubles back into floats and fix their code,
since
 thats where 99% of precision problems actually come from.

I was forced to figure out how they work in excruciating detail, as I had to write an emulator in case the user didn't have an 8087. Actually, that knowledge has served me well.
Aug 19 2012
prev sibling parent Sean Cavanaugh <WorksOnMyMachine gmail.com> writes:
On 8/20/2012 12:41 AM, Nick Sabalausky wrote:
 On Sun, 19 Aug 2012 01:21:03 -0500
 Sean Cavanaugh<WorksOnMyMachine gmail.com>  wrote:
 Nobody knows how floats work, without being locked in a closet for a
 at least a week and told to change their doubles back into floats and
 fix their code, since thats where 99% of precision problems actually
 come from.

Sorry, I don't understand, where are you saying 99% of precision problems come from?

Chaining algorithms together without regard to how the floats are propagated through the system. Also, accumulating lots of values with addition and subtraction can be problematic, as can subtracting two values to near-zero values also leaves you with a most of the error. There is a pretty classic example in 3d graphics: the transform from object space to world space to projection space. Even if these matrices are combined, your geometry can be transformed a very large distance from the world origin and lose a lot of precision in the process. The way to fight this is to use camera instead of world space as much as possible. If you don't do this all the vertices on all the meshes in your world snap to different values at varying rates when they move or the camera moves, causing one of the main forms of z-fighting. Plus the further you get from your world origin the worse things get, which makes building something on the scale of an open-world game rather difficult.
Aug 20 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/19/2012 4:48 AM, Peter Alexander wrote:
 Yes, I got this impression as well. What a sad state of affairs.

Yup. NaNs just don't get no respect, I tell ya! No respect at all!
Aug 19 2012
parent "Mike James" <foo bar.com> writes:
"Walter Bright"  wrote in message news:k0rhp5$2fud$2 digitalmars.com... 

On 8/19/2012 4:48 AM, Peter Alexander wrote:
 Yes, I got this impression as well. What a sad state of affairs.

Yup. NaNs just don't get no respect, I tell ya! No respect at all! NaNs are the Rodney Dangerfield of D...
Aug 19 2012
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
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".
Aug 18 2012
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
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.
Aug 18 2012
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sat, 18 Aug 2012 21:12:33 -0700
Jonathan M Davis <jmdavisProg gmx.com> wrote:
 
 FWIW, I'm very surprised by how negatively many programmers seem to
 react to NaN. I think that how D handles it is great. 

Yea, it's kind of like Unicode: ASCII is much simpler and therefore far more enticing. But unfortunately we have to deal with reality and reality dictates that NaNs and non-ASCII chars exist and must be taken into consideration.
Aug 18 2012
prev sibling next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Sunday, 19 August 2012 at 05:13:09 UTC, dennis luehring wrote:
 Am 19.08.2012 06:12, schrieb Jonathan M Davis:
 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.

i think many of these programmers seems to think that D is introducing this NaN-Type ...

Yes, I got this impression as well. What a sad state of affairs.
Aug 19 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Walter Bright:

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

This D code compiles and it throws an "Enforcement failed" Exception at runtime: import std.typecons: Nullable; void main() { Nullable!int x; int y = x; } With a different type system the compiler makes sure at compile-time that x is not empty (this means the compiler makes sure in no code paths x is used before testing it contains something), avoiding the run-time exception. Bye, bearophile
Aug 19 2012
prev sibling next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Sunday, 19 August 2012 at 14:14:00 UTC, Michel Fortin wrote:
 On 2012-08-19 05:54:49 +0000, Walter Bright 
 <newshound2 digitalmars.com> said:

 On 8/18/2012 9:21 PM, Nick Sabalausky wrote:
 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".

I'm less willing to throw default initialization out - I like it & rely on it. The C# approach pretty much ends default initialization, including for user defined types.

I like default initialization too, and I rely on it. By that I mean that all the time I write "size_t count;" and assume it'll be default initialized to zero. I like it because it's less typing and it's simple: if I don't assign anything it's zero. I can't do that for floats or chars, because the default initialization gives me a unusable value. In my mind C#-style conservative flow analysis errors are better than default initialization to a bogus value because they catch the problem at compile time. But on the other side I'd rather not give up on integer default initialization to zero, as I actually prefer this over everything else. So Walter, which default initialization do you like an rely on? As I said, personally, I'd have everything initialized to zero by default. But at this point you can't really change this even if you want to: some program somewhere might rely on float being initialized to NaN by default and might start to give erroneous results if you change the default. (Notice the irony?)

The problem with implicit initialisation to zero is that it is indistinguishable from simply forgetting to initialise the value. There's three scenarios here: 1. You intentionally relied on implicit initialisation: GOOD. 2. You forgot, 0 wasn't what you wanted, but the error shows up quickly: NOT BAD 3. You forgot, 0 wasn't what you wanted, but the error is subtle/rare: BAD #3 is where the nasty bugs come in. From my experience, these bugs have the potential to be monsters, and in my opinion, avoiding them is far more important than saving a couple of keystrokes in initialisation. There's two solutions: 1. Conservative compile-time error on uninitialised variables. 2. Initialise to a value that will make scenario #2 more likely than scenario #3 (e.g. NaN) Personally, I'd prefer option 1. Walter's argument is that this "leads to the programmer getting annoyed with false positive error diagnostics, and he'll likely add an =0", which is true, but in my opinion this scenario is quite rare to start with, and it's even more rare that 0 isn't actually the right initialisation value, and even then it's only a problem if the introduced bug is hard to reproduce. I find it more likely that the NaN will go unnoticed and cause rare bugs.
Aug 19 2012
prev sibling next sibling parent reply Chad J <chadjoan __spam.is.bad__gmail.com> writes:
On 08/17/2012 08:03 PM, 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_respect/


 http://www.drdobbs.com/cpp/nans-just-dont-get-no-respect/240005723

Walter, I know you like to make the easy thing the right thing. I like this notion myself. So instead of writing float f; if (condition1) f = 7; ... code ... if (condition2) ++f; is there any way we can make it easier to write void someCode() { ... code ... } float f; if ( condition ) { f = 7; someCode(); ++f; } else someCode(); assuming that condition2 is true when condition1 is true? Maybe some other reasonable equivalent snippet could be concocted that's easier to discover, and make the language hint in that direction. I feel like NaNs are a step forward, but better can be done. They allow error detection, but it's still merely runtime error detection, and worse yet, it's /non-local/ error detection. NaNs can spread from function to function and end up in completely different parts of a program than the place they originated. This causes debugging hell, just like null values. It makes me think that non-nan-able floating point types would be very useful, at least as function arguments, so that calling code doesn't have to introduce extra checks for NaNs that are either lost cycles or forgotten entirely and bug-ridden. I really wish we had a way of catching NaNs in the function or line where they happen, and not in completely distant parts of the code.
Aug 19 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/19/2012 1:43 PM, Chad J wrote:
 So instead of writing

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

 is there any way we can make it easier to write

      void someCode() {
          ... code ...
      }

      float f;
      if ( condition )
      {
          f = 7;
          someCode();
          ++f;
      }
      else
          someCode();

 assuming that condition2 is true when condition1 is true?

Yes, you can do that.
 I feel like NaNs are a step forward, but better can be done.  They allow error
 detection, but it's still merely runtime error detection, and worse yet, it's
 /non-local/ error detection.  NaNs can spread from function to function and end
 up in completely different parts of a program than the place they originated.
 This causes debugging hell, just like null values.

I'm sorry, it's not debugging hell. I've done an awful lot of "figure out where this null came from" and it's a bit tedious, but not hell. You go step by step, such as "it's null in this function, so put an assert on the callers of the function", rinse, repeat. Yes, I also know this is more of a problem if you've got a program that's not so easy to rerun.
 It makes me think that
 non-nan-able floating point types would be very useful, at least as function
 arguments, so that calling code doesn't have to introduce extra checks for NaNs
 that are either lost cycles or forgotten entirely and bug-ridden.

You can use signalling NaNs, if you like.
 I really wish we had a way of catching NaNs in the function or line where they
 happen, and not in completely distant parts of the code.

Nobody has even mentioned this until I brought it up, so I have a hard time believing the current state of affairs is a terrible problem that requires a major redesign to fix. I know that nobody wants to see NaNs in their results, but be assured that that is far, far better than corrupted results that are off in subtle ways. NaNs are also one hell of a lot easier to track backwards than the other.
Aug 19 2012
parent reply Chad J <chadjoan __spam.is.bad__gmail.com> writes:
On 08/19/2012 06:16 PM, Walter Bright wrote:
 On 8/19/2012 1:43 PM, Chad J wrote:
 So instead of writing

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

 is there any way we can make it easier to write

 void someCode() {
 ... code ...
 }

 float f;
 if ( condition )
 {
 f = 7;
 someCode();
 ++f;
 }
 else
 someCode();

 assuming that condition2 is true when condition1 is true?

Yes, you can do that.
 I feel like NaNs are a step forward, but better can be done. They
 allow error
 detection, but it's still merely runtime error detection, and worse
 yet, it's
 /non-local/ error detection. NaNs can spread from function to function
 and end
 up in completely different parts of a program than the place they
 originated.
 This causes debugging hell, just like null values.

I'm sorry, it's not debugging hell. I've done an awful lot of "figure out where this null came from" and it's a bit tedious, but not hell. You go step by step, such as "it's null in this function, so put an assert on the callers of the function", rinse, repeat. Yes, I also know this is more of a problem if you've got a program that's not so easy to rerun.

Most of the programs I've worked on, be it hobby games or business apps for pay, have been interactive stuff. Rerunning sucks. Debuggers also interact very poorly with these things, or just plain have crappy interfaces that make using them a legitimate pain. My productivity is greatly improved by NOT having to do tedious busywork. This is why I have a very low tolerance for non-local bugs and a lack of good stacktrace info when crashing. I'd feel /a lot/ better if corrupt data like NaNs or nulls would create some kind of a crash or compiler error /before/ leaving the function that created them. IMO, this would be a huge step forward for programmer productivity. No longer does every nan/null take like 15-30 minutes to debug, it takes 1 minute instead.
 It makes me think that
 non-nan-able floating point types would be very useful, at least as
 function
 arguments, so that calling code doesn't have to introduce extra checks
 for NaNs
 that are either lost cycles or forgotten entirely and bug-ridden.

You can use signalling NaNs, if you like.

How? I remember reading a lot of material on NaNs in D, but I don't recall these.
 I really wish we had a way of catching NaNs in the function or line
 where they
 happen, and not in completely distant parts of the code.

Nobody has even mentioned this until I brought it up, so I have a hard time believing the current state of affairs is a terrible problem that requires a major redesign to fix.

I doubt that preventing non-local bug propagation would require any kind of major redesign at this point. D seems very close already. Some kind of convenient notation for optional non-nullable (and maybe non-nan-able?) types combined with strictly simple branching initializations and some kind of easy-to-use sentinel values would probably go a long way. There seems to be a push to try and get this functionality from user-defined types. I am skeptical that it will ever work for these things because something like NotNull!MyType foo( NotNull!MyType a, NotNan!float b ) { ... } is going to be very daunting to write and read compared to something like MyType foo( MyType a, float b ) which is just a notation I've seen in previous posts. Initialization becomes a huge pain for the user-defined types too. Not only are proxy types like "NotNull!X" far more difficult to write in D than I would have expected, but things like non-null types and possibly non-nan types would be so common that things will probably look very nasty if people start using proxy types for this. I'm willing to wait and see if these proxy types can be made though, and if they get used a lot. I just hope their clumsiness doesn't inhibit their use. I understand it's easier to add things in demand than it is to remove things that are used infrequently.
 I know that nobody wants to see NaNs in their results, but be assured
 that that is far, far better than corrupted results that are off in
 subtle ways. NaNs are also one hell of a lot easier to track backwards
 than the other.

I agree that NaNs are really cool. They are definitely much better than "f=0;". Thank you for doing this.
Aug 19 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/19/2012 6:33 PM, Chad J wrote:
 How?  I remember reading a lot of material on NaNs in D, but I don't recall
these.

Set the control word for the x87 to turn it on. Probably have to do a little inline assembly.
Aug 19 2012
parent reply Chad J <chadjoan __spam.is.bad__gmail.com> writes:
On 08/20/2012 11:09 AM, Andrej Mitrovic wrote:
 On 8/20/12, Walter Bright<newshound2 digitalmars.com>  wrote:
 On 8/19/2012 6:33 PM, Chad J wrote:
 How?  I remember reading a lot of material on NaNs in D, but I don't
 recall these.

Set the control word for the x87 to turn it on. Probably have to do a little inline assembly.

I thought you could do by setting FloatingPointControl in std.math.

That looks much more convenient and clean. Gotta make the right thing easy to do, right? <g> How thread-local is it?
Aug 21 2012
parent Don Clugston <dac nospam.com> writes:
On 21/08/12 16:14, renoX wrote:
 On Tuesday, 21 August 2012 at 12:25:45 UTC, Chad J wrote:
 On 08/20/2012 11:09 AM, Andrej Mitrovic wrote:
 On 8/20/12, Walter Bright<newshound2 digitalmars.com>  wrote:
 On 8/19/2012 6:33 PM, Chad J wrote:
 How?  I remember reading a lot of material on NaNs in D, but I don't
 recall these.

Set the control word for the x87 to turn it on. Probably have to do a little inline assembly.

I thought you could do by setting FloatingPointControl in std.math.

That looks much more convenient and clean. Gotta make the right thing easy to do, right? <g>

Except that it doesn't seem to work as expected (maybe an old compiler's bug..)

Yeah, there's a bug in the code generation, at the moment for 80-bit reals it works on AMD but not Intel processors (!)
Aug 21 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 8/20/12, Walter Bright <newshound2 digitalmars.com> wrote:
 On 8/19/2012 6:33 PM, Chad J wrote:
 How?  I remember reading a lot of material on NaNs in D, but I don't
 recall these.

Set the control word for the x87 to turn it on. Probably have to do a little inline assembly.

I thought you could do by setting FloatingPointControl in std.math.
Aug 20 2012
prev sibling parent "renoX" <renozyx gmail.com> writes:
On Tuesday, 21 August 2012 at 12:25:45 UTC, Chad J wrote:
 On 08/20/2012 11:09 AM, Andrej Mitrovic wrote:
 On 8/20/12, Walter Bright<newshound2 digitalmars.com>  wrote:
 On 8/19/2012 6:33 PM, Chad J wrote:
 How?  I remember reading a lot of material on NaNs in D, but 
 I don't
 recall these.

Set the control word for the x87 to turn it on. Probably have to do a little inline assembly.

I thought you could do by setting FloatingPointControl in std.math.

That looks much more convenient and clean. Gotta make the right thing easy to do, right? <g>

Except that it doesn't seem to work as expected (maybe an old compiler's bug..) RenoX
 How thread-local is it?

Aug 21 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sun, 19 Aug 2012 22:18:37 +0200, Walter Bright  
<newshound2 digitalmars.com> wrote:

 On 8/19/2012 5:08 AM, bearophile wrote:
 With a different type system the compiler makes sure at compile-time  
 that x is
 not empty (this means the compiler makes sure in no code paths x is  
 used before
 testing it contains something), avoiding the run-time exception.

That's called disabling the default constructor with disable.

Nope. What bearophile is talking about is something more akin to this, I think: Nullable!int a; int x = a; // Compile-time error: a might be null! if ( a ) { int y = a; // 's fine, we know it's not null. } -- Simen
Aug 19 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sun, 19 Aug 2012 05:52:01 +0200, Walter Bright  
<newshound2 digitalmars.com> wrote:

 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

Like someone on Reddit mentioned, VHDL has 9 boolean states: 'U': uninitialized. This signal hasn't been set yet. 'X': unknown. Impossible to determine this value/result. '0': logic 0 '1': logic 1 'Z': High Impedance 'W': Weak signal, can't tell if it should be 0 or 1. 'L': Weak signal that should probably go to 0 'H': Weak signal that should probably go to 1 '-': Don't care. -- Simen
Aug 19 2012
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sun, 19 Aug 2012 14:08:17 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 Walter Bright:

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

This D code compiles and it throws an "Enforcement failed" Exception at runtime: import std.typecons: Nullable; void main() { Nullable!int x; int y = x; } With a different type system the compiler makes sure at compile-time that x is not empty (this means the compiler makes sure in no code paths x is used before testing it contains something), avoiding the run-time exception.

We could define a Nullable!T that does not allow access to the payload value, and only give that access inside a special function, like pattern matching in other languages: Nullable!int a; int n = a.match!( (int x) => x, (None n) => 0 ); -- Simen
Aug 19 2012
prev sibling next sibling parent "Minas Mina" <minas_mina1990 hotmail.co.uk> writes:
I was against nan being the dafault value, but now I that I think 
about it, it is useful (for the reasons in the article).
Aug 19 2012
prev sibling next sibling parent FeepingCreature <default_357-line yahoo.de> writes:
See Subject :)
Aug 19 2012
prev sibling next sibling parent Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sun, 19 Aug 2012 01:21:03 -0500
Sean Cavanaugh <WorksOnMyMachine gmail.com> wrote:
 
 Nobody knows how floats work, without being locked in a closet for a
 at least a week and told to change their doubles back into floats and
 fix their code, since thats where 99% of precision problems actually
 come from.
 

Sorry, I don't understand, where are you saying 99% of precision problems come from?
Aug 19 2012
prev sibling next sibling parent Leandro Lucarella <luca llucax.com.ar> writes:
Walter Bright, el 18 de August a las 12:11 me escribiste:
 On 8/18/2012 6:51 AM, Peter Alexander wrote:
Maybe it's related to the tendency for programmers to be libertarians, which
would also explain the whole open source software movement. They want to share
knowledge freely, and online articles would be part of that.

I find this peculiar, as the open source software movement is frequently associated with communism, not libertarianism. (Although I do think it is much more correct to associate it with libertarianism.)

Well, free software[1] is closer to communism (or socialism), open source (as in the OSD)[2] is closer to libertarianism. "Open source is a development methodology; free software is a social movement." -- Richard Stallman [1] http://en.wikipedia.org/wiki/The_Free_Software_Definition [2] http://opensource.org/docs/osd -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Cuando le dije si quería bailar conmigo Se puso a hablar de Jung, de Freud y Lacan Mi idiosincracia le causaba mucha gracia Me dijo al girar la cumbiera intelectual
Aug 20 2012
prev sibling next sibling parent Caligo <iteronvexor gmail.com> writes:
--000e0ce07b187f2ed504c7b36d2a
Content-Type: text/plain; charset=ISO-8859-1

Any chance that math.isNaN() will work at compile-time in the future?
http://d.puremagic.com/issues/show_bug.cgi?id=8562

I haven't had the chance to study the source since last night, but is it
not possible to check to see if something is a nan without doing a cast?

On Fri, Aug 17, 2012 at 7:03 PM, Walter Bright
<newshound2 digitalmars.com>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_respect/<http://www.reddit.com/r/programming/comments/yehz4/nans_just_dont_get_no_respect/>

 http://www.drdobbs.com/cpp/**nans-just-dont-get-no-respect/**240005723<http://www.drdobbs.com/cpp/nans-just-dont-get-no-respect/240005723>

--000e0ce07b187f2ed504c7b36d2a Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Any chance that math.isNaN() will work at compile-time in the future?=A0 <a= href=3D"http://d.puremagic.com/issues/show_bug.cgi?id=3D8562" target=3D"_b= lank">http://d.puremagic.com/issues/show_bug.cgi?id=3D8562</a><br><br>I hav= en&#39;t had the chance to study the source since last night, but is it not= possible to check to see if something is a nan without doing a cast?<br> <br><div class=3D"gmail_quote">On Fri, Aug 17, 2012 at 7:03 PM, Walter Brig= ht <span dir=3D"ltr">&lt;<a href=3D"mailto:newshound2 digitalmars.com" targ= et=3D"_blank">newshound2 digitalmars.com</a>&gt;</span> wrote:<br><blockquo= te class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc so= lid;padding-left:1ex"> Our discussion on this in the last few days inspired me to write a blog pos= t about it:<br> <br> <a href=3D"http://www.reddit.com/r/programming/comments/yehz4/nans_just_don= t_get_no_respect/" target=3D"_blank">http://www.reddit.com/r/<u></u>program= ming/comments/yehz4/<u></u>nans_just_dont_get_no_respect/</a><br> <br> <a href=3D"http://www.drdobbs.com/cpp/nans-just-dont-get-no-respect/2400057= 23" target=3D"_blank">http://www.drdobbs.com/cpp/<u></u>nans-just-dont-get-= no-respect/<u></u>240005723</a><br> </blockquote></div><br> --000e0ce07b187f2ed504c7b36d2a--
Aug 20 2012
prev sibling next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Sunday, 19 August 2012 at 22:22:28 UTC, Walter Bright wrote:
 I find it more likely that the NaN will go unnoticed and
 cause rare bugs.

NaNs in your output are pretty obvious. For example, if your accounting program prints "NAN" for the amount on the payroll cheques, someone is guaranteed to notice. But if it's a few cents off in your disfavor, it might take you years to discover there's a problem. Critical systems also would find a NaN command a lot easier to detect than an off-by-two command, and would be able to shut down and engage the backup.

The problem is that it's easy for even NaN's to be filtered out. float x = 0.0f; float y; // oops float z = min(x, y); // NaN has disappeared, unnoticed! My argument is that conservative compile time errors on uninitialised variables are more likely to catch these errors.
Aug 20 2012
prev sibling next sibling parent "cal" <callumenator gmail.com> writes:
On Monday, 20 August 2012 at 19:28:33 UTC, Peter Alexander wrote:
 On Sunday, 19 August 2012 at 22:22:28 UTC, Walter Bright wrote:
 I find it more likely that the NaN will go unnoticed and
 cause rare bugs.

NaNs in your output are pretty obvious. For example, if your accounting program prints "NAN" for the amount on the payroll cheques, someone is guaranteed to notice. But if it's a few cents off in your disfavor, it might take you years to discover there's a problem. Critical systems also would find a NaN command a lot easier to detect than an off-by-two command, and would be able to shut down and engage the backup.

The problem is that it's easy for even NaN's to be filtered out. float x = 0.0f; float y; // oops float z = min(x, y); // NaN has disappeared, unnoticed! My argument is that conservative compile time errors on uninitialised variables are more likely to catch these errors.

I just tried this: float a, b = 10; writeln(min(a, b), ", ", fmin(a, b)); Result: nan, 10 I think that is incorrect - both should give NaN. The scientific viz software I use at work returns NaN for any numerical operation on NaN values, means, smoothing, etc.
Aug 20 2012
prev sibling next sibling parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Monday, 20 August 2012 at 20:21:12 UTC, cal wrote:
 I just tried this:

 float a, b = 10;
 writeln(min(a, b), ", ", fmin(a, b));

 Result:
 nan, 10

 I think that is incorrect - both should give NaN. The 
 scientific viz software I use at work returns NaN for any 
 numerical operation on NaN values, means, smoothing, etc.

It's tricky. The only way (that I'm aware of) to get it to return NaN is to explicitly test for NaN, introducing overhead that is unnecessary 99.9% of the time. Unfortunately this is one of those situations where D's design goals of efficiency and safety are at odds. You can't have it both ways.
Aug 20 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Peter Alexander:

 It's tricky. The only way (that I'm aware of) to get it to 
 return NaN is to explicitly test for NaN, introducing overhead 
 that is unnecessary 99.9% of the time.

 Unfortunately this is one of those situations where D's design 
 goals of efficiency and safety are at odds. You can't have it 
 both ways.

Few possibilities: 1) Add a second NaN-aware function pair nmax()/nmin(); 2) Add a debug{} inside min()/max(), where NaNs are managed; 3) Introduce a if(version=NaNAware){} block inside the normal max()/min() and other Phobos functions, to be used when you want more NaN-correct results. I prefer the third idea, but this probably requires a recompilation of Phobos. Bye, bearophile
Aug 20 2012
prev sibling next sibling parent "renoX" <renozyx gmail.com> writes:
On Monday, 20 August 2012 at 19:28:33 UTC, Peter Alexander wrote:
[cut]
 The problem is that it's easy for even NaN's to be filtered out.

 float x = 0.0f;
 float y; // oops
 float z = min(x, y); // NaN has disappeared, unnoticed!

In theory, one could prevent this by setting the floating point control word to trigger a trap when reading a NaN which I think *should* be the default. Unfortunately it doesn't seem to work, there is an FPE in the code below, where it shouldn't. Then again, the online compiler I've tried is very old: dmd-2.042.


int main() { FloatingPointControl fpc; fpc.enableExceptions(FloatingPointControl.severeExceptions); float x = 0.0f; float y; // oops y=1; float z = min(x, y); writeln("min x,y=",z); return 0; } <<
Aug 21 2012
prev sibling parent "cal" <callumenator gmail.com> writes:
On Tuesday, 21 August 2012 at 08:15:10 UTC, Don Clugston wrote:
 No, it's the other way around.
 The IEEE 754 standard defines min(x, NaN) == min(NaN, x) == x.

 According to the C standard, fmin() should be returning 10, as 
 well.
 There is a bug in fmin().

 However min() and max() are extremely unusual in this respect. 
 Almost everything else involving a NaN returns NaN.

I did not know that. It seems like a not-so-useful rule but I guess they have their reasons. Note that in my example, fmin() _did_ return 10 - it was min() that returned NaN...
Aug 21 2012