String.toNumber() causes invalid value error in CIQ1 but returns null in CIQ2/siim

String.toNumber() and toFloat() cause invalid value error in CIQ1, return null in CIQ2/simulator, when a string that does not start with a number is passed.

I know that the documentation says this will happen, but the behaviour is still inconsistent. I get that the CIQ1 behaviour may never change due to limited VM space, but it would be nice if:
- The simulator had the same behaviour
- The behaviour for CIQ2 devices (return null) was documented

I previously checked whether the first char was a number or not, but I wanted to save code space. Clearly that was a mistake.

Environment
CIQ SDK 2.3.2
FR935 FW 5.10 (null)
FR920XT FW9.30 (invalid value)
(I have reason to believe this also happens on Fenix 3 HR)

Reproduction procedure
Create a simple data field with the attached code.

Run it on CIQ2 device or simulator (any device).

Output looks like:
x = hello world
x.toNumber() = null
x.toFloat() = null


Run it on CIQ1 device and it crashes with an Invalid Value error (just like the doc says).

// Set the label of the data field here.
function initialize<[]> {
SimpleDataField.initialize<[]>;
label = "My Label";

var x = "hello world";
var y = x.toNumber<[]>;
System.println<["x = " + x]>;
System.println<["x.toNumber<[]> = " + y]>;

var z = x.toNumber<[]>;
System.println<["x.toFloat<[]> = " + z]>;

}





  • I don't think his is an implementation bug. It is working exactly as it is supposed to, the docs are just out of date.

    Fixing this on old devices would require a firmware update, which may not happen for some devices.

    You might consider rolling your own implementation so you have control over the exact behavior. Neither function (toNumber or toFloat) should be difficult to implement. I posted code for one in this thread.

    Travis
  • The docs say that an Invalid Value error will be thrown if the string doesn't start with a number will result in an invalid value error.

    You could use this to your advantage... make a copy of the string and put a 1 at the front. Do the conversion. If you get 1 back, it wasn't a number. Otherwise, it was a number, and you can just do the conversion on the original string and get the right result.
  • Travis, I agree with everything you said, except I wish the simulator would generate the same error when you simulate CIQ1 devices. I'm sure that:
    1) There may not be enough room in the VM to "fix" this
    2) Even if it gets fixed, some CIQ1 devices may not get the fix

    My main concern is that I can't be sure exactly what will happen on older devices by running the app in the simulator, and this is not the first time I've seen that. I did read the documentation, but the simulator does not do what the documentation says. How can I be sure which one is correct/intended? I have also seen cases where the doc is awkwardly written, and gives the impression that a function is supported by certain devices when in fact, the opposite is true,

    At the very least, the docs could be updated:
    CIQ1: Invalid Value error is thrown
    CIQ2: null is returned

    For the app in question, I broke every coding rule in the book (including getting rid of almost all classes and replacing enum/consts with hardcoded values) in order to squeeze out every last byte of memory, because it's a configurable app which takes user input whose length is only limited by the amount of free memory (and the length of config strings in GCM/GE). The more free memory the app has, the more useful it is to the user. I actually had several CIQ2-only functions which I added to CIQ1 devices, after finding all kinds of (mostly terrible) ways to save memory.

    For a "normal" app with bounded memory usage and fixed input length, I would definitely do one of those things. For my specific app, I want to remove every last line of unnecessary code. So I just bit the bullet and put the code back in to the check the first char. I know it's not a huge amount of memory, but if I do that ten times, it def makes a difference in what the app is able to do on older devices.

    I do find it interesting that the CIQ1 behaviour is to generate an error (not even an exception) that crashes the app, and the CIQ2 behaviour is to return null. It seems like both behaviours would require the same amount of code to implement. It's almost as if someone decided it would be nicer to return null instead of crashing. After all, for CIQ1, String.toNumber() and String.toFloat() almost always have to be accompanied/wrapped with code that checks the string for validity, at least if the string comes from user input. But those calls already check the string for validity. It's just that in CIQ1, they give the app no chance to recover from an invalid string.

    I'll also say that I don't know of many other languages/OSs where a library function crashes the application when converting a string to a number. Unless I'm mistaken, Invalid Value is not even an exception you can catch. (Similar to Array out of Bounds). It's just a hard error that forcefully terminates your app.

    Even C's atoi() returns 0, and strtol() sets errno. Since Monkey C has a dedicated null value which is not a number, seems like it would've been a great candidate for an error value from the start.

    Thanks for the suggestions.
  • I'd do a try/catch or something. The 1.x VM on a watch probably won't change..

    it's like:
    var num="08";
    var a=num.toNumber()

    (and "a" won't be the same on 1.x/2.x in some cases!)
  • Thanks!

    I already accepted that the VM probably won't change, but as I said, it would be nice if the simulator reflected the actual behaviour. Next time I will definitely code more defensively. At one point I went through a process of cutting out all the fat in my app, since it allowed me to add several features to CIQ1 devices which had previously been CIQ2 only. Obviously I went a tiny bit too far by removing a check that I thought was redundant.

    Also, please correct me if I'm wrong, but I believe Invalid Value is a fatal error which can't be caught (much like an array out of bounds error). That is part of my gripe, although what's done is done. I just don't think being unable to convert a string to a number should be a fatal error. And apparently someone else didn't think so which is why (I'm guessing) the behaviour has been changed.

    In contrast, array out of bounds being a fatal error is understandable (although it would've been nice if that were an exception).
  • If you read through the posts in the thread I linked to above, you'll see that Brian.ConnectIQ mentioned that there was a ticket filed to make Invalid Value errors catchable. I've got no idea what the state of that issue is, but it doesn't matter much for this particular case; ConnectIQ 2.x devices will not throw an Invalid Value error, and ConnectIQ 1.x devices aren't likely to get a firmware update which (I believe) is required to get the change in place on devices.

    Honestly, I'd like to see many of the fatal errors in ConnectIQ changed to exceptions. Array Out Of Bounds, Initializer Error, Invalid Value, Null Reference, Out of Memory, Permission Required, Symbol Not Found, Too Many Timers and Unexpected Type errors all seem like things an application should be able to handle.
  • Former Member
    Former Member over 8 years ago
    Hey,

    I have reported this as a Simulator Bug. We do our best to make the sim closely match the devices. Thank you all for the hard work.

    Thanks,
    -Coleman