I'm aware that this might cause some trouble changing now, but I also don't see why this wasn't considered right from the word go.
0.0 may well be a desired result but the distinction isn't possible without extra tests, for which I'd just stick with the extra test and not at all check for 0.0.
However if breaking existing code has to be avoided at all cost, how about adding an optional bool* success or even double* retValOrNAN?
Same for String::toInt(), Stream::parseFloat() and Stream::parseInt().
What's the behaviour of the Arduino SDK for these functions?
I fear it's just the same 0.0 as this is the default behaviour of the underlying strtof(), atof(), ...
But as with other topics (e.g. serialEvent() :wink:) where Arduino has become the pseudo-standard for better or rather worse, letting us being limited by that may be arguable.
Maybe this proposal could be made on the Arduino side too to break the ground
However, I did try
https://github.com/arduino/Arduino/issues/7177
A similar proposal was turned down already
https://github.com/arduino/Arduino/issues/1796
Concurred. It's bad mojo to have silent failures, esp. when the computer knows something went wrong and it simply doesn't forward that info on to the user. These kind of awkward situations are what leads to brittle code and surprising bugs...
For things like this, I feel compatibility flags are a good way forward. That means we can fix the bug, but for anyone dependent upon the old behaviour, setting a flag reverts to the old behaviour.
Of course, it does mean that people read the changelogs for each release and add the compatibility flags for behaviour that has changed that they wish to preserve.
To make it more concrete, in 0.7.0, we expect this to be true:
String("Hello").toFloat()==0.0f
In a later release when we fix this behavior, then that will no longer be true and NaN is returned.
String("Hello").toFloat()==NaN
But if someone really wants the old behavior/compatibility with Arduino then using a feature flag would bring the old behaviour back. This might be particularly important with libraries, where fixes may take more time to appear compared to your own application.
#define PARTICLE_STRING_TOFLOAT_ZERO_ON_ERROR
// ... and in the same file
String("Hello").toFloat()==0.0f
There are many nuances here, such as ensuring library behaviour doesn't change when upgrading system firmware or changing defaults. A scheme where each library indicated the version of system firmware it targets would be a good step so that we can try to ensure backwards compatibility for each library. This means that String.toFloat() would behave differently depending upon which library is calling it (or specifically, the compatibility version of system firmware associated with the library.)
Another option which, while a little messy, would fit the Arduino style (and maintain 100% backwards compatibility), would be to have an overloaded useNaN parameter. String("aaa").toFloat() would continue to return 0.0, but String("aaa").toFloat(true) would return NaN.
Any existing code, or future code ported from Arduino, will use the original toFloat(), while developers writing new code for Particle could be encouraged to use the overloaded version. This also avoids the use of pointers, which seems to be a common theme in Arduino-style code (probably to make things more beginner-friendly).
Most helpful comment
For things like this, I feel compatibility flags are a good way forward. That means we can fix the bug, but for anyone dependent upon the old behaviour, setting a flag reverts to the old behaviour.
Of course, it does mean that people read the changelogs for each release and add the compatibility flags for behaviour that has changed that they wish to preserve.
To make it more concrete, in 0.7.0, we expect this to be true:
In a later release when we fix this behavior, then that will no longer be true and NaN is returned.
But if someone really wants the old behavior/compatibility with Arduino then using a feature flag would bring the old behaviour back. This might be particularly important with libraries, where fixes may take more time to appear compared to your own application.
There are many nuances here, such as ensuring library behaviour doesn't change when upgrading system firmware or changing defaults. A scheme where each library indicated the version of system firmware it targets would be a good step so that we can try to ensure backwards compatibility for each library. This means that
String.toFloat()would behave differently depending upon which library is calling it (or specifically, the compatibility version of system firmware associated with the library.)