Jump to page: 1 27  
Page
Thread overview
floats default to NaN... why?
Apr 14, 2012
F i L
Apr 14, 2012
Jonathan M Davis
Apr 14, 2012
F i L
Apr 14, 2012
Jonathan M Davis
Apr 14, 2012
F i L
Apr 14, 2012
Jonathan M Davis
Apr 14, 2012
F i L
Jun 06, 2012
ixid
Jun 08, 2012
Minas
Jun 08, 2012
Kevin Cox
Jun 08, 2012
Minas
Jun 08, 2012
Jerome BENOIT
Jun 09, 2012
Andrew Wiley
Jun 09, 2012
Minas
Jun 09, 2012
Kevin
Jun 09, 2012
Jerome BENOIT
Jun 09, 2012
Kevin
Jun 09, 2012
Jerome BENOIT
Jun 09, 2012
Andrew Wiley
Jun 09, 2012
Andrew Wiley
Jun 10, 2012
Jerome BENOIT
Apr 14, 2012
Jerome BENOIT
Apr 14, 2012
F i L
Apr 14, 2012
Jerome BENOIT
Apr 14, 2012
F i L
Apr 14, 2012
Jerome BENOIT
Apr 14, 2012
F i L
Apr 14, 2012
Jerome BENOIT
Apr 16, 2012
F i L
Apr 16, 2012
F i L
Apr 16, 2012
Jerome BENOIT
Apr 16, 2012
F i L
Apr 16, 2012
bearophile
Apr 16, 2012
F i L
Apr 16, 2012
Ary Manzana
Apr 16, 2012
F i L
Apr 14, 2012
Andrej Mitrovic
Apr 14, 2012
Manfred Nowak
Apr 14, 2012
F i L
Apr 14, 2012
Silveri
Apr 14, 2012
F i L
Apr 14, 2012
Manfred Nowak
Jun 05, 2012
Don Clugston
Apr 14, 2012
dennis luehring
Apr 14, 2012
F i L
Apr 14, 2012
dennis luehring
Apr 14, 2012
F i L
Apr 14, 2012
Ali Çehreli
Apr 14, 2012
Jonathan M Davis
Apr 14, 2012
F i L
Apr 14, 2012
Jonathan M Davis
Apr 14, 2012
bearophile
Apr 14, 2012
Andrej Mitrovic
Apr 14, 2012
F i L
Apr 14, 2012
Andrej Mitrovic
Apr 14, 2012
F i L
Apr 14, 2012
Andrej Mitrovic
Apr 14, 2012
F i L
Apr 14, 2012
Andrej Mitrovic
Apr 14, 2012
F i L
Jun 10, 2012
Jonathan M Davis
Jun 10, 2012
Jerome BENOIT
Jun 10, 2012
Jerome BENOIT
April 14, 2012
From the FaQ:

> NaNs have the interesting property in that whenever a NaN is used as an operand in a computation, the result is a NaN. Therefore, NaNs will propagate and appear in the output whenever a computation made use of one. This implies that a NaN appearing in the output is an unambiguous indication of the use of an uninitialized variable.

> If 0.0 was used as the default initializer for floating point values, its effect could easily be unnoticed in the output, and so if the default initializer was unintended, the bug may go unrecognized.


So basically, it's for debugging? Is that it's only reason? If so I'm at loss as to why default is NaN. The priority should always be in the ease-of-use IMO. Especially when it breaks a "standard":

    struct Foo {
      int x, y;    // ready for use.
      float z, w;  // messes things up.
      float r = 0; // almost always...
    }

I'm putting this in .Learn because I'm not really suggesting a change as much as trying to learn the reasoning behind it. The break in consistency doesn't outweigh any cost of "debugging" benefit I can see. I'm not convinced there is any. Having core numerical types always and unanimously default to zero is understandable and consistent (and what I'm use too with C#). The above could be written as:

    struct Foo {
      float z = float.nan, ...
    }

if you wanted to guarantee the values are set uniquely at construction. Which seems like a job better suited for unittests to me anyways.

musing...
April 14, 2012
On Saturday, April 14, 2012 06:00:35 F i L wrote:
>  From the FaQ:
> > NaNs have the interesting property in that whenever a NaN is used as an operand in a computation, the result is a NaN. Therefore, NaNs will propagate and appear in the output whenever a computation made use of one. This implies that a NaN appearing in the output is an unambiguous indication of the use of an uninitialized variable.
> > 
> > If 0.0 was used as the default initializer for floating point values, its effect could easily be unnoticed in the output, and so if the default initializer was unintended, the bug may go unrecognized.
> 
> So basically, it's for debugging? Is that it's only reason? If so I'm at loss as to why default is NaN. The priority should always be in the ease-of-use IMO. Especially when it breaks a "standard":
> 
>      struct Foo {
>        int x, y;    // ready for use.
>        float z, w;  // messes things up.
>        float r = 0; // almost always...
>      }
> 
> I'm putting this in .Learn because I'm not really suggesting a change as much as trying to learn the reasoning behind it. The break in consistency doesn't outweigh any cost of "debugging" benefit I can see. I'm not convinced there is any. Having core numerical types always and unanimously default to zero is understandable and consistent (and what I'm use too with C#). The above could be written as:
> 
>      struct Foo {
>        float z = float.nan, ...
>      }
> 
> if you wanted to guarantee the values are set uniquely at construction. Which seems like a job better suited for unittests to me anyways.
> 
> musing...

Types default to the closest thing that they have to an invalid value so that code blows up as soon as possible if you fail to initialize a variable to a proper value and so that it fails deterministically (unlike when variables aren't initialized and therefore have garbage values).

NaN is the invalid value for floating point types and works fantastically at indicating that you screwed up and failed to initialize or assign your variable a proper value. null for pointers and references works similarily well.

If anything, the integral types and bool fail, because they don't _have_ invalid values. The closest that they have is 0 and false respectively, so that's what they get. It's the integral types that are inconsistent, not the floating point types.

It was never really intended that variables would be default initialized with values that you would use. You're supposed to initialize them or assign them to appropriate values before using them. Now, since the default values are well-known and well-defined, you can rely on them if you actually _want_ those values, but the whole purpose of default initialization is to make code fail deterministically when variables aren't properly initialized - and to fail as quickly as possible.

- Jonathan M Davis
April 14, 2012
Am 14.04.2012 06:00, schrieb F i L:
>       struct Foo {
>         int x, y;    // ready for use.
>         float z, w;  // messes things up.
>         float r = 0; // almost always...
>       }

how often in your code is 0 or 0.0 the real starting point?
i can't think of any situation except counters or something
where 0 is a proper start - and float 0.0 is in very very few cases a normal start - so whats your point?
April 14, 2012
So it's what I thought, the only reason is based on a faulty premise, IMO.

Jonathan M Davis wrote:
> Types default to the closest thing that they have to an invalid value so that
> code blows up as soon as possible if you fail to initialize a variable to a
> proper value and so that it fails deterministically

This seems like exactly opposite behavior I'd expect from the compiler. Modern convenience means more bang per character, and initializing values to garbage is the corner case, not the usual case.

> (unlike when variables
> aren't initialized and therefore have garbage values).

This is the faulty premise I see. Garbage values are a C/C++ thing. They must be forced in D, eg, float x = void.

I would argue that because values *should* have implicit, non-garbage, default values that those default values should be the most commonly used/expected "lowest" value. Especially since ints _must_ be 0 (though I hear this is changing in Arm64).


> NaN is the invalid value for floating point types and works fantastically at
> indicating that you screwed up and failed to initialize or assign your
> variable a proper value.

> null for pointers and references works similarily
> well.

Not exactly. NaNs don't cause Segfaults or Undefined behavior, they just make the math go haywire. It's like it was designed to be inconvenient. The argument looks like this to me:

"We default values so there's no garbage-value bugs.. but the default is something that will cause a bug.. because values should be explicitly defaulted so they're not unexpected values (garbage).. even though we could default them to an expected value since we're doing it to begin with"

It sounds like circular reasoning.


> It was never really intended that variables would be default initialized with
> values that you would use.

why exactly? again, this is a faulty premise IMO.


> You're supposed to initialize them or assign them
> to appropriate values before using them.

sure, but if they always default to _usable_ constants no expectations are lost and no bugs are created.


> Now, since the default values are
> well-known and well-defined, you can rely on them if you actually _want_ those
> values,

yes, and how often do you _want_ a NaN in the mix? You can rely on usable values just as much. Even more so since Ints and Floats would be consistent.


> but the whole purpose of default initialization is to make code fail
> deterministically when variables aren't properly initialized - and to fail as
> quickly as possible.

that only makes sense in C/C++ where value are implicitly garbage and mess things up.


Again, this is only my perspective. I would love to hear convincing arguments to how great D currently defaulting to NaN is, and how much headache (I never knew I had) it will save me... but I just don't see it. In fact I'm now more convinced of the opposite. Never in C# have I ran into issues with unexpected values from default initializers. Most important values are set at runtime through object constructors; not at declaration.
April 14, 2012
On Saturday, 14 April 2012 at 05:19:38 UTC, dennis luehring wrote:
> Am 14.04.2012 06:00, schrieb F i L:
>>      struct Foo {
>>        int x, y;    // ready for use.
>>        float z, w;  // messes things up.
>>        float r = 0; // almost always...
>>      }
>
> how often in your code is 0 or 0.0 the real starting point?
> i can't think of any situation except counters or something
> where 0 is a proper start - and float 0.0 is in very very few cases a normal start - so whats your point?

Every place that a structure property is designed to be mutated externally. Almost all Math structures, for instance.

Defaults are to combat garbage values, but debugging cases where values where accidentally unset (most likely missed during construction) seems like a better job for a unittest.

April 14, 2012
On Saturday, April 14, 2012 07:41:33 F i L wrote:
> > You're supposed to initialize them or assign them
> > to appropriate values before using them.
> 
> sure, but if they always default to _usable_ constants no expectations are lost and no bugs are created.

No. You always have a bug if you don't initialize a variable to the value that it's supposed to be. It doesn't matter whether it's 0, NaN, 527.1209823, or whatever. All having a default value that you're more likely to use means is that you're less likely to have to explicitly initialize the variable. It has to be initialized to the correct value regardless. And if you're in the habit of always initializing variables and never relying on the defaults if you can help it, then the cases where variables weren't initialized to what they were supposed to be stand out more.

> > but the whole purpose of default initialization is to make code
> > fail
> > deterministically when variables aren't properly initialized -
> > and to fail as
> > quickly as possible.
> 
> that only makes sense in C/C++ where value are implicitly garbage and mess things up.

??? D was designed with an eye to improve on C/C++. In C/C++, variables aren't guaranteed to be initialized, so if you forget to initialize them, you get garbage, which is not only buggy, it results in non-deterministic behavior. It's always a bug to not initialize a variable. D's approach is to say that it's _still_ a bug to not initialize a variable, since you almost always need to initialize a variable to something _other_ than a default. But rather than leaving them as garbage, D makes it so that variables are default-initialized, making the buggy behavior deterministic. And since not initializing a variable is almost always a bug, default values which were the closest to error values for each type were chosen.

You can disagree with the logic, but there it is. I don't see how it's an issue, since you almost always need to initialize variables to something other than the default, and so leaving them as the default is almost always a bug.

The only point of dispute that I see in general is whether it's better to rely on the default or to still explicitly initialize it when you actually want the default. Relying on the default works, but by always explicitly initializing variables, those which are supposed to be initialized to something other than the defaults but aren't are then much more obvious.

Regardless, the _entire_ reason for default-initialization in D revolves around making buggy initializations deterministic and more detectable.

- Jonathan M Davis
April 14, 2012
On 04/13/2012 09:00 PM, F i L wrote:

> default is NaN

Just to complete the picture, character types have invalid initial values as well: 0xFF, 0xFFFF, and 0x0000FFFF for char, wchar, and dchar, respectively.

Ali

April 14, 2012
On Friday, April 13, 2012 23:29:40 Ali Çehreli wrote:
> On 04/13/2012 09:00 PM, F i L wrote:
>  > default is NaN
> 
> Just to complete the picture, character types have invalid initial values as well: 0xFF, 0xFFFF, and 0x0000FFFF for char, wchar, and dchar, respectively.

Yeah. Thanks for mentioning those. I keep forgetting to list them whenever default values get discussed...

- Jonathan M Davis
April 14, 2012
F i L wrote:

> It sounds like circular reasoning.

Several considerations pressed the design into the current form:
1) always changing output on unchanged input is hard to debug
2) GC needs to be saved from garbage, that looks like pointers
3) missed explicit initializations should not create syntax errors
4) use hardware signalling to overcome some of the limitations
impressed by 3).
5) more???

For me the only questionable point is numer three.

-manfred
April 14, 2012
Jonathan M Davis wrote:
> No. You always have a bug if you don't initialize a variable to the value that
> it's supposed to be. It doesn't matter whether it's 0, NaN, 527.1209823, or
> whatever. All having a default value that you're more likely to use means is
> that you're less likely to have to explicitly initialize the variable. It has
> to be initialized to the correct value regardless.

Yes, I'm in favor of default values. That's not my argument here. I'm saying it makes more sense to have the default values be _usable_ (for convenience) rather than designed to catch (**cause**) bugs.


> And if you're in the habit
> of always initializing variables and never relying on the defaults if you can
> help it,

That seams like a very annoying habit requirement for a languages with a focus on "modern convenience". What's more bug prone, I think, is forcing developers to remember that unset floats (specifically) will cause bugs while it's neighboring int works perfectly without a explicit value.


> then the cases where variables weren't initialized to what they were
> supposed to be stand out more.

Usable defaults don't need to stand out because they're usable and deterministic. If you want to make sure a constructor/method produces expected results, unittest it.. it makes more sense to catch errors at compile time anyways.




> D's approach is to say that
> it's _still_ a bug to not initialize a variable, since you almost always need
> to initialize a variable to something _other_ than a default.

Not always, but that's besides the point. The point is that in the places where you do want zero values (Vector/Matrix/etc, Polygon structs, counters, etc..) it's better to have consistent expected behavior from the default value. Not some value that causes runtime bugs.


> I don't see how it's an
> issue, since you almost always need to initialize variables to something other
> than the default, and so leaving them as the default is almost always a bug.

To me, it's not a huge issue, only an annoyance. However I wouldn't underestimate the impact of bad marketing. When people are trying out the language, and they read "variables are defaulted, not garbage" do you think they're going to expect ints and floats to work in different ways?

And it doesn't cause bugs to default value types to zero. I have enough experience with C# to know that it doesn't. All it does is make the language more consistent.


> The only point of dispute that I see in general is whether it's better to rely
> on the default or to still explicitly initialize it when you actually want the
> default.

This sounds like an argument for C++. Explicit declaration isn't a guard against bugs, you'll still be hunting through code if something is incorrectly set.

The fact of the matter is default initialization _does_ happen in code, no matter how philosophically correct "always explicitly define value" might be. Unless that's enforced, it can and should be expected to happen. That given, it's more convenient to have consistent value type behavior. Float is a Value type and shouldn't be subjective to the security concerns of Reference types.


> Regardless, the _entire_ reason for default-initialization in D revolves
> around making buggy initializations deterministic and more detectable.

The same way string, and int are defaulted to usable values, float should be as well. Catching code that works with null pointers is one thing. Working with a value type without requiring the programmer have deeper knowledge about D's asymmetrical features is another.

If D doesn't accommodate entering Laymen, how does it expect to gain popularity in any major way? Efficiency puts D on the map, convenience is what brings the tourists.

I'm not trying to convince you that the sky is falling because I disagree with D's direction with floats.. just if the goal is to increase D's popularity, little things may turn heads away quicker than you think. My original post was inspired by me showing my D code to another C# guy earlier, and coming up with poor explanations as to why floats where required to be defaulted in my math lib. His reaction what along the lines of my first post.
« First   ‹ Prev
1 2 3 4 5 6 7