Invalid double value '2.454' for locale 'en_CA'

Hi,

I have this method

    method convertValue(value:NSString):Double;
    begin
      exit Convert.ToDouble(value);
    end;

On the watch os simulator it works fine but on a physical device I get

MyWatchApp WatchKit Extension[538:348534] *** Terminating app due to uncaught exception ‘Exception’, reason: 'Invalid double value ‘2.454’ for locale en_CA’

***** First throw call stack:**

Its using Toffee

Cheers,
John

I think its this line of code

I changed my code to be

      if String.IsNullOrEmpty(value) then
      begin
        NSLog('IsNullOrEmpty');
        exit 0;
      end;
      
      var aLocale := new NSLocale withLocaleIdentifier('en_CA');
      

      var Formatter := new NSNumberFormatter;
      Formatter.numberStyle := NSNumberFormatterStyle.NSNumberFormatterDecimalStyle;
      Formatter.locale := aLocale;
      if (value as PlatformString).rangeOfCharacterFromSet(NSCharacterSet.whitespaceAndNewlineCharacterSet).location ≠ NSNotFound then // NSNumberFormatter ignores (some) whitespace, we wanna fail
      begin
        NSLog('whitespace');
        exit 0;
      end;
      //if value.StartsWith("+") and not value.Contains("-") then // NSNumberFormatter doesn't like +, strip it;
      //  value := valuee.Substring(1);
      NSLog('numberFromString');
      exit Formatter.numberFromString(value).doubleValue;
      {$ENDIF}
      
    end;

And it logs whitespace

doubtful, ad that would just return nil?

if yu call

Formatter.numberFromString(aValue);

manually, do yu get the same error? i assume en_CA is Canada, does canada use “.” as decimal separator like the US do, or do you/they use “,” (like eg Germany)?

That would mean your input string has whitespace then, or else could this be hit!?

Yes its Canada, the code works fine on my mac. On the watch the method is being called from swift. I don’t think it contains whitespace because if I remove the rangeOfCharacterFromSet is returns the correct double.

The swift code is

let obj = Class1()
        let roundedValue = obj.convertValue("2.454")

I did an NSLog(‘location %ld’, range.location) from the watch with and simulator and I get
9223372036854775807 and 9798692

I was wondering if the architectures might be different like one is 64bit and the other is 32 but then
I was looking at what NSNotFound was declared as and its 32bit max int.

Ok, so just to be clear

this line

exit Convert.ToDouble(value);

gives you the exception " 'Invalid double value ‘2.454’ for locale en_CA’". (Can you get the full; call stack, to see whether that is from inside Formatter.numberFromString or ot (but it really has to be),

but if instead you duplicate the code from Convert.ToDouble locally, you hit the “exit ni;” clause — with the excact same input string?

What happens if you just do

  var Formatter := new NSNumberFormatter;
  Formatter.numberStyle := NSNumberFormatterStyle.NSNumberFormatterDecimalStyle;
  Formatter.locale := "en_CA";
  result := Formatter.numberFromString(aValue);

locally in your code?

hm, that’s not good, and might explain why you hit the exit clause, but it doesn’t explain why you don’t when using Convert.ToDouble from RTL2 (i’m assuming the binary we ship, not locally rebuilt?)…

in either case, that would just be hiding the exception from Formatter.numberFromString.

So exit Convert.ToDouble does this

I think the exception is coming from RTL2 code, it matches the formatexception.

On Toffee ToDouble calls TryParseNumber and thats what I copied . I have to run on the watch because I cant repro on my mac. Its also the binary you ship.

If I fix it a bit

      var Formatter := new NSNumberFormatter;
      Formatter.numberStyle := NSNumberFormatterStyle.NSNumberFormatterDecimalStyle;
      Formatter.locale := new NSLocale withLocaleIdentifier('en_CA');
      result := Formatter.numberFromString(value).doubleValue;

This code works.

I think its something about NSRange on the device. Even if i dont use the passed in string i return odd vales in location

This does sound a bitness bug for arm64_32, yeah. can you do me a favor and run the following code for watchOS simulator, watchOS device as armv7k and watchOS arm64_32? And can you also enable the “Generate IR” option, and zip up[ and post the generated .ll for all architectures (just zip up the entire ./bin folder for the lib)?

      NSLog("ProcessArchitecture %@", Environment.ProcessArchitecture);
      NSLog("ProcessBitness %d", Environment.ProcessBitness);
      NSLog("OSArchitecture %@", Environment.OSArchitecture);
      NSLog("OSBitness %d", Environment.OSBitness);
      
      var aValue: NSString := "2.454";
      var aLocation := (aValue as PlatformString).rangeOfCharacterFromSet(NSCharacterSet.whitespaceAndNewlineCharacterSet).location;
      NSLog("aLocation %ld", aLocation);
      NSLog("NSNotFound %ld", NSNotFound);
      NSLog("!=? %d", aLocation ≠ NSNotFound);

      NSLog("aLocation %@", Convert.ToHexString(aLocation));
      NSLog("NSNotFound %@", Convert.ToHexString(NSNotFound));

fwiw, i get this on macOS arm64

2022-01-18 18:05:00.228580-0400 ConsoleApplication25[48243:693126] ProcessArchitecture arm64
2022-01-18 18:05:00.228950-0400 ConsoleApplication25[48243:693126] ProcessBitness 64
2022-01-18 18:05:00.228965-0400 ConsoleApplication25[48243:693126] OSArchitecture arm64
2022-01-18 18:05:00.229047-0400 ConsoleApplication25[48243:693126] OSBitness 64
2022-01-18 18:05:00.229194-0400 ConsoleApplication25[48243:693126] aLocation 9223372036854775807
2022-01-18 18:05:00.229225-0400 ConsoleApplication25[48243:693126] NSNotFound 9223372036854775807
2022-01-18 18:05:00.229245-0400 ConsoleApplication25[48243:693126] !=? 0
2022-01-18 18:05:00.229482-0400 ConsoleApplication25[48243:693126] aLocation 7FFFFFFFFFFFFFFF
2022-01-18 18:05:00.229560-0400 ConsoleApplication25[48243:693126] NSNotFound 7FFFFFFFFFFFFFFF

Logged as bugs://E25638.

What did you mean by running the watchOS device as armv7k and arm64_32 ?

I ran the code in the simulator and got

2022-01-19 08:18:43.875169-0500 MyWatchApp WatchKit Extension[14540:4111680] ProcessArchitecture armv7k
2022-01-19 08:18:43.875337-0500 MyWatchApp WatchKit Extension[14540:4111680] ProcessBitness 64
2022-01-19 08:18:43.875524-0500 MyWatchApp WatchKit Extension[14540:4111680] OSArchitecture armv7k
2022-01-19 08:18:43.875632-0500 MyWatchApp WatchKit Extension[14540:4111680] OSBitness 64
2022-01-19 08:18:43.875719-0500 MyWatchApp WatchKit Extension[14540:4111680] aLocation 9223372036854775807
2022-01-19 08:18:43.875776-0500 MyWatchApp WatchKit Extension[14540:4111680] NSNotFound 9223372036854775807
2022-01-19 08:18:43.875904-0500 MyWatchApp WatchKit Extension[14540:4111680] !=? 0
2022-01-19 08:18:43.876282-0500 MyWatchApp WatchKit Extension[14540:4111680] aLocation 7FFFFFFFFFFFFFFF
2022-01-19 08:18:43.876394-0500 MyWatchApp WatchKit Extension[14540:4111680] NSNotFound 7FFFFFFFFFFFFFFF

and on my watch and got

2022-01-19 08:32:06.394903-0500 MyWatchApp WatchKit Extension[928:980382] ProcessArchitecture arm64_32
2022-01-19 08:32:06.395104-0500 MyWatchApp WatchKit Extension[928:980382] ProcessBitness 32
2022-01-19 08:32:06.395192-0500 MyWatchApp WatchKit Extension[928:980382] OSArchitecture arm64_32
2022-01-19 08:32:06.395267-0500 MyWatchApp WatchKit Extension[928:980382] OSBitness 32
2022-01-19 08:32:06.395351-0500 MyWatchApp WatchKit Extension[928:980382] aLocation 705803600
2022-01-19 08:32:06.395420-0500 MyWatchApp WatchKit Extension[928:980382] NSNotFound 2147483647
2022-01-19 08:32:06.395489-0500 MyWatchApp WatchKit Extension[928:980382] !=? 1
2022-01-19 08:32:06.397441-0500 MyWatchApp WatchKit Extension[928:980382] aLocation 2A11B550
2022-01-19 08:32:06.397816-0500 MyWatchApp WatchKit Extension[928:980382] NSNotFound 7FFFFFFF

The generate ir option seem exposed in a multi target project is this ok ?

  <PropertyGroup Condition=" '$(Target)' == 'Toffee.watchOS' ">
    <Mode>Toffee</Mode>
    <SDK>watchOS</SDK>
    <DefaultUses>Foundation;RemObjects.Elements.Linq</DefaultUses>
    <GenerateBitcode>True</GenerateBitcode>
    <Architecture>all</Architecture>
    <SimulatorArchitecture>all</SimulatorArchitecture>
    <GenerateIRFile>True</GenerateIRFile>
  </PropertyGroup>

Bin.zip (689.0 KB)

Like iOS and macOS, watchOS supports two architectures, the older pure 32-bit armv7k, and the newer “mostly” 64-bit arm64_32.

thanx. definitely something going wrong here…

Should be fine, yes. thanx!

I’m gonna run a new SDK import for you. what version of Xcode/watchOS do you need, to build against?

watch os 8.3 and xcode 13.2.1

1 Like

Should be fixed (compiler-side) for vNext. thanx!

(20220119-152906-elements-develop)

1 Like

I tried with the lines of code above and that worked but my library gives me a slightly different message

WatchKit Extension[1031:1257100] *** Terminating app due to uncaught exception ‘Exception’, reason: 'Invalid double value ‘1.28’ for locale '

It’s calling into JsonDeserializer and eventually calling Convert.ToDouble. When you said should be fixed compiler side are there other things I need ?

No, there shouldn’t. But that said, the fix was of cousre as yet untested. Does your standaalone test case still fail, too? ie

var aValue: NSString := "2.454";
      var aLocation := (aValue as PlatformString).rangeOfCharacterFromSet(NSCharacterSet.whitespaceAndNewlineCharacterSet).location;
      NSLog("aLocation %ld", aLocation);
      NSLog("NSNotFound %ld", NSNotFound);

?

Oh, actually the build you grabed mighty not have bneen a full rebuiltd, and thus not have RTL2 rebuilt with the latest compiler. i’ll initiate a full rebuild.

1 Like

Is the full build still running ?