www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Floating point types default to NaN?

reply A Guy With a Question <aguywithaquestion gmail.com> writes:
I would have expected 0 to be the default value. What's the logic 
behind having them being NaN by default?

https://dlang.org/spec/type.html
Nov 24 2017
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 24 November 2017 at 14:30:44 UTC, A Guy With a 
Question wrote:
 I would have expected 0 to be the default value. What's the 
 logic behind having them being NaN by default?
It gives you a runtime error (sort of) if you use an uninitialized variable. You ARE supposed to explicitly initialize variables to your own values in D. The automatic init is to make errors stand out more consistently if you don't do this as opposed to being random. So pointers are initialized to null - an invalid value that stands out if you try to use it. chars get \xFF - again, invalid that will throw if you try to utf decode it. Floats get NaN which is as close to invalid as they get. ints happen to get 0 not to be convenient, but because there is no clearly-invalid int value so something had to be chosen, and 0 was just easy to implement....
Nov 24 2017
parent reply A Guy With a Question <aguywithaquestion gmail.com> writes:
On Friday, 24 November 2017 at 14:43:24 UTC, Adam D. Ruppe wrote:
 On Friday, 24 November 2017 at 14:30:44 UTC, A Guy With a 
 Question wrote:
 I would have expected 0 to be the default value. What's the 
 logic behind having them being NaN by default?
It gives you a runtime error (sort of) if you use an uninitialized variable. You ARE supposed to explicitly initialize variables to your own values in D. The automatic init is to make errors stand out more consistently if you don't do this as opposed to being random. So pointers are initialized to null - an invalid value that stands out if you try to use it. chars get \xFF - again, invalid that will throw if you try to utf decode it. Floats get NaN which is as close to invalid as they get. ints happen to get 0 not to be convenient, but because there is no clearly-invalid int value so something had to be chosen, and 0 was just easy to implement....
If thats the case why not just throw a compiler error? D has a way explicitly not set it right? Through void...So if the intent is to find erroneous code right away, just throw a compiler error no?
Nov 24 2017
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, November 24, 2017 20:43:14 A Guy With a Question via Digitalmars-
d-learn wrote:
 On Friday, 24 November 2017 at 14:43:24 UTC, Adam D. Ruppe wrote:
 On Friday, 24 November 2017 at 14:30:44 UTC, A Guy With a

 Question wrote:
 I would have expected 0 to be the default value. What's the
 logic behind having them being NaN by default?
It gives you a runtime error (sort of) if you use an uninitialized variable. You ARE supposed to explicitly initialize variables to your own values in D. The automatic init is to make errors stand out more consistently if you don't do this as opposed to being random. So pointers are initialized to null - an invalid value that stands out if you try to use it. chars get \xFF - again, invalid that will throw if you try to utf decode it. Floats get NaN which is as close to invalid as they get. ints happen to get 0 not to be convenient, but because there is no clearly-invalid int value so something had to be chosen, and 0 was just easy to implement....
If thats the case why not just throw a compiler error? D has a way explicitly not set it right? Through void...So if the intent is to find erroneous code right away, just throw a compiler error no?
That requires data flow analysis, which the compiler doesn't do a lot of, because it can be complicated. It also tends to result in the compiler giving warnings or errors in cases where it's not actually true that the variable is used before it's given a value, because it can't do it perfectly. There was a recent discussion on this in the main newsgroup with regards to guaranteeing with a pointer or reference was initialized to something other than null. Also, when you start having stuff like arrays, having a default initializer is a big boon, since then all of the elements have a default value. It's going to work even worse to try and have the compiler detect when you've properly initialized every element in an array than have it detect when you've properly initialized just a variable. And stuff like the out attribute relies on there being a default initializer. Just all around, having default initializers for types in general makes things cleaner and less error-prone. And NaN math is something that's built into CPU. Operations other than default initialization can result in a floating point value being NaN. So, if you're looking to have NaN not be a thing for floating point values, then you're out of luck. And Walter is a big fan of NaN being a thing, since when you hit it, you know that you've found a bug, and tracking it down tends to be fairly straightforward, which is not the case with many other types of bugs. - Jonathan M Davis
Nov 24 2017
next sibling parent reply Dave Jones <dave jones.com> writes:
On Friday, 24 November 2017 at 22:38:49 UTC, Jonathan M Davis 
wrote:
 On Friday, November 24, 2017 20:43:14 A Guy With a Question via 
 Digitalmars- d-learn wrote:
 On Friday, 24 November 2017 at 14:43:24 UTC, Adam D. Ruppe
That requires data flow analysis, which the compiler doesn't do a lot of, because it can be complicated. It also tends to result in the compiler giving warnings or errors in cases where it's not actually true that the variable is used before it's given a value, because it can't do it perfectly. There was a recent discussion on this in the main newsgroup with regards to guaranteeing with a pointer or reference was initialized to something other than null.
I think he means just spew an error if a float is declared but not explicitly initialised... Whats the problem with... float foo; // compiler error "floats must be explicitly initialised" float foo = float.nan; // old behaviour. I mean at the end of the day, that would turn a run time error into a compile time error which is a good thing isnt it?
Nov 25 2017
next sibling parent reply A Guy With a Question <aguywithaquestion gmail.com> writes:
On Saturday, 25 November 2017 at 09:39:15 UTC, Dave Jones wrote:
 On Friday, 24 November 2017 at 22:38:49 UTC, Jonathan M Davis 
 wrote:
 On Friday, November 24, 2017 20:43:14 A Guy With a Question 
 via Digitalmars- d-learn wrote:
 On Friday, 24 November 2017 at 14:43:24 UTC, Adam D. Ruppe
That requires data flow analysis, which the compiler doesn't do a lot of, because it can be complicated. It also tends to result in the compiler giving warnings or errors in cases where it's not actually true that the variable is used before it's given a value, because it can't do it perfectly. There was a recent discussion on this in the main newsgroup with regards to guaranteeing with a pointer or reference was initialized to something other than null.
I think he means just spew an error if a float is declared but not explicitly initialised... Whats the problem with... float foo; // compiler error "floats must be explicitly initialised" float foo = float.nan; // old behaviour. I mean at the end of the day, that would turn a run time error into a compile time error which is a good thing isnt it?
That is exactly what I meant. I think most languages just choose to default it to something convenient, which is 0. C++ chooses not to default it for speed reasons. If D chooses it's defaults to make errors stick out, why not just error at declaration if they don't explicitly set it to something. Including void, which would give you C++ undefined behavior from what I've read so far.
Nov 25 2017
next sibling parent A Guy With a Question <aguywithaquestion gmail.com> writes:
Nonetheless, my original question was answered. Thanks for the 
insights!
Nov 25 2017
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 25 November 2017 at 16:16:52 UTC, A Guy With a 
Question wrote:
 If D chooses it's defaults to make errors stick out, why not 
 just error at declaration if they don't explicitly set it to 
 something.
It technically did: https://dlang.org/spec/function.html#local-variables "It is an error to use a local variable without first assigning it a value. The implementation may not always be able to detect these cases. Other language compilers sometimes issue a warning for this, but since it is always a bug, it should be an error. " But that paragraph was never implemented (it is a bit easier said than done to actually detect given if conditions and stuff too, especially in the early days of D when the compiler didn't even make any effort to track such things, though it does now...). The compiler author took the easy way out of initializing them to invalid values instead. While it is more realistic to implement technically now than it was years ago when the current behavior got in, I think we're at the point now that so many people use it as a convenience thing on ints and nulls that there'd be hell to pay if the compiler actually started calling it an error :(
Nov 25 2017
next sibling parent A Guy With a Question <aguywithaquestion gmail.com> writes:
On Saturday, 25 November 2017 at 22:13:43 UTC, Adam D. Ruppe 
wrote:
 On Saturday, 25 November 2017 at 16:16:52 UTC, A Guy With a 
 Question wrote:
 If D chooses it's defaults to make errors stick out, why not 
 just error at declaration if they don't explicitly set it to 
 something.
It technically did: https://dlang.org/spec/function.html#local-variables "It is an error to use a local variable without first assigning it a value. The implementation may not always be able to detect these cases. Other language compilers sometimes issue a warning for this, but since it is always a bug, it should be an error. " But that paragraph was never implemented (it is a bit easier said than done to actually detect given if conditions and stuff too, especially in the early days of D when the compiler didn't even make any effort to track such things, though it does now...). The compiler author took the easy way out of initializing them to invalid values instead. While it is more realistic to implement technically now than it was years ago when the current behavior got in, I think we're at the point now that so many people use it as a convenience thing on ints and nulls that there'd be hell to pay if the compiler actually started calling it an error :(
Fair enough!
Nov 25 2017
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 11/25/17 5:13 PM, Adam D. Ruppe wrote:
 On Saturday, 25 November 2017 at 16:16:52 UTC, A Guy With a Question wrote:
 If D chooses it's defaults to make errors stick out, why not just 
 error at declaration if they don't explicitly set it to something.
It technically did: https://dlang.org/spec/function.html#local-variables "It is an error to use a local variable without first assigning it a value. The implementation may not always be able to detect these cases. Other language compilers sometimes issue a warning for this, but since it is always a bug, it should be an error. " But that paragraph was never implemented (it is a bit easier said than done to actually detect given if conditions and stuff too, especially in the early days of D when the compiler didn't even make any effort to track such things, though it does now...). The compiler author took the easy way out of initializing them to invalid values instead. While it is more realistic to implement technically now than it was years ago when the current behavior got in, I think we're at the point now that so many people use it as a convenience thing on ints and nulls that there'd be hell to pay if the compiler actually started calling it an error :(
I rely on the default value initialization all the time! I don't know how that would jive with structs, since they are technically local variables, but usually are valid without initialization. What about AAs? Would you have to do = []? -Steve
Nov 27 2017
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 27 November 2017 at 14:58:42 UTC, Steven Schveighoffer 
wrote:
 I rely on the default value initialization all the time! I 
 don't know how that would jive with structs, since they are 
 technically local variables, but usually are valid without 
 initialization.
Yes, indeed, me too. I like it now. But there might be a compromise that is still workable: let structs and ints (and bytes, short, etc) be exceptions and not issue an error there. But then conservatively check other types. If the compiler sees any read before any write, issue the error. Otherwise, keep the status quo. That's fit the spec and catch real bugs more often than false positives. Though, I'm in no ruse to see that implemented either, overall I am meh on it.
 What about AAs? Would you have to do = []?
they could be an exception too, but you could do = null (= [] won't pass the type check lol)
Nov 27 2017
prev sibling parent reply Michael V. Franklin <slavo5150 yahoo.com> writes:
On Saturday, 25 November 2017 at 22:13:43 UTC, Adam D. Ruppe 
wrote:

 It technically did:

 https://dlang.org/spec/function.html#local-variables

 "It is an error to use a local variable without first assigning 
 it a value. The implementation may not always be able to detect 
 these cases. Other language compilers sometimes issue a warning 
 for this, but since it is always a bug, it should be an error. "


 But that paragraph was never implemented (it is a bit easier 
 said than done to actually detect given if conditions and stuff 
 too, especially in the early days of D when the compiler didn't 
 even make any effort to track such things, though it does 
 now...). The compiler author took the easy way out of 
 initializing them to invalid values instead.
WOW!! I am shocked to learn this. All this time, I though it was a design oversight. I think I'm going to implement a feature gate to require explicit initialization. It would be better to be strict up front and relax it as flow control analysis becomes more mature. Mike
Nov 27 2017
parent reply Michael V. Franklin <slavo5150 yahoo.com> writes:
On Monday, 27 November 2017 at 23:05:55 UTC, Michael V. Franklin 
wrote:

 I think I'm going to implement a feature gate to require 
 explicit initialization.  It would be better to be strict up 
 front and relax it as flow control analysis becomes more mature.
Well, I implemented it (https://github.com/dlang/dmd/pull/7375), but it's off to a pretty rocky start. Mike
Nov 28 2017
parent reply A Guy With a Question <aguywithanquestion gmail.com> writes:
On Tuesday, 28 November 2017 at 20:00:53 UTC, Michael V. Franklin 
wrote:
 On Monday, 27 November 2017 at 23:05:55 UTC, Michael V. 
 Franklin wrote:

 I think I'm going to implement a feature gate to require 
 explicit initialization.  It would be better to be strict up 
 front and relax it as flow control analysis becomes more 
 mature.
Well, I implemented it (https://github.com/dlang/dmd/pull/7375), but it's off to a pretty rocky start. Mike
To be honest, I didn't actually expect anyone to act on my question. :D I was just more curious of the design decisions that were made.
Nov 28 2017
parent reply Michael V. Franklin <slavo5150 yahoo.com> writes:
On Wednesday, 29 November 2017 at 01:24:21 UTC, A Guy With a 
Question wrote:

 I was just more curious of the design decisions that were made.
So am I. I'm trying to get to the heart of in the the PR comments. Mike
Nov 28 2017
parent A Guy With a Question <aguywithanquestion gmail.com> writes:
On Wednesday, 29 November 2017 at 01:25:47 UTC, Michael V. 
Franklin wrote:
 On Wednesday, 29 November 2017 at 01:24:21 UTC, A Guy With a 
 Question wrote:

 I was just more curious of the design decisions that were made.
So am I. I'm trying to get to the heart of in the the PR comments. Mike
That's a lot less code than I would have thought to implement that. The comment about phobos was a good one. Just reading through it.
Nov 28 2017
prev sibling parent reply Dukc <ajieskola gmail.com> writes:
On Saturday, 25 November 2017 at 09:39:15 UTC, Dave Jones wrote:
 I mean at the end of the day, that would turn a run time error 
 into a compile time error which is a good thing isnt it?
Debatable in this case. Consider: string servicePhoneNumber; final switch (car.manufacturer) //an enumerated value. { case CarMaker.Audi: servicePhoneNumber = staff["Dorff Hans"].phone; //... break; case CarMaker.Skoda: servicePhoneNumber = staff["Telegin Svetlana"].phone; //... break; //more cases ... } Here it is arguably unnecessary typing if you had to manually set servicePhoneNumber to "" or something at start. And in case of structs it tends to be a verbose thing to manually set one to it's init value.
Nov 27 2017
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 27 November 2017 at 16:04:14 UTC, Dukc wrote:
 Debatable in this case. Consider:

 string servicePhoneNumber;

 final switch (car.manufacturer) //an enumerated value.
Well, the compiler can see it is initialized before being read again later, so that *should* pass the check (at least conservatively- the spec is flexible enough to let the compiler not catch them all).
Nov 27 2017
prev sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Friday, 24 November 2017 at 22:38:49 UTC, Jonathan M Davis 
wrote:
 That requires data flow analysis, which the compiler doesn't do 
 a lot of, because it can be complicated.
If dataflow is sufficient then it isn't all that complicated, you can implement generic dataflow using Monotone Frameworks: http://symbolaris.com/course/Compilers11/27-monframework.pdf But on the other hand, data flow might not be sufficient for what you want to do.
 And NaN math is something that's built into CPU. Operations 
 other than default initialization can result in a floating 
 point value being NaN.
If you have turned on exceptions for signalling-NaNs then it makes sense. It doesn't make all that much sense for quiet NaNs.
Nov 25 2017
prev sibling parent codephantom <me noyb.com> writes:
On Friday, 24 November 2017 at 14:30:44 UTC, A Guy With a 
Question wrote:
 I would have expected 0 to be the default value. What's the 
 logic behind having them being NaN by default?

 https://dlang.org/spec/type.html
http://www.drdobbs.com/cpp/nans-just-dont-get-no-respect/240005723
Nov 29 2017