is newly constructed array filled with 0-s?

var a = new Number[7];
Can I assume that a is filled with 0-s, or do I need to make sure by looping over it ad assigning 0-s to each item?
  • From my test, arrays are filled with nulls after new (and even I use this feature).

    var
            //a1 = new Number[2],      compiler error Cannot resolve type 'Number'.
            a2 = new[2];
            //lg(a1);
            lg(a2);

    console:

    [null, null]

  • Yes, a1 won't compile.

    var a=new[7]; //gives you an array with 7 nulls;

    var a=[0,0,0,0,0,0,0];  //gives you an array with 7 zeros

    and you can have a ByteArray by adding "b" like this:

    var ba=[0,0,0,0,0,0,0]b;

  • it doesn't give a compiler error:
    heartRateZones = new Number[6];

    compiles with the strictest params:
    java -Xms1g -Dfile.encoding=UTF-8 -Dapple.awt.UIElement=true -jar ~/.Garmin/ConnectIQ/Sdks/connectiq-sdk-lin-4.1.7-2022-11-21-562b8a195/bin/monkeybrains.jar -o bin/test.prg -f monkey.jungle -y developer_key.der -d fenix6_sim -w -l 3 -O2z
    However it fills it with nulls instead of 0-s, which is a shame because I wanted to save code. Changing it to:
    var zero = 0;
    heartRateZones = [zero, zero, zero, zero, zero, zero] as Array<Number>;
    adds 67 bytes to the code Disappointed
    while changing it to:
    heartRateZones = [0, 0, 0, 0, 0, 0] as Array<Number>;
    adds 78 bytes Disappointed

    and:

    heartRateZones = new Number[6];
    for (var i = 0; i < 6; i++) {heartRateZones[i]=0;}
    adds 41 bytes

    if you change it to:
    heartRateZones = new Number[6];
    for (var i = zero; i < 6; i++) {heartRateZones[i]=zero;}
    then it only adds 35 bytes. this is the best (I also use zero = 0 in other place in the same function, so this is a little bit cheating)


    Let's see if anyone can come up with one with less bytes !

     

  • If your values are all 0-255, using a ByteArray when it's available will save you a whole bunch of memory.  You only use 1 byte per index, vs an object per index.

  • maybe if you only look at the construction, but I have many places where I index it, so unless Garmin add ByteArray.get(i), and ByteArray.set(i, v) it won't really help me IMHO, and even if it did it would be a relatively big logical refactoring. If it was just replacing: h[i] with g.get(i) and h[i]=v with h.set(i,v) then I would try it but since I'll need to find a way to emulate these by feeling is that it'll add more code instead of remove some...

  • You can use an index in a ByteArray just like in an Array if you are dealing with 0-255.  encodeNumber/decodeNumber can be used if you want signed 8 bit,16 bit, 32 bit, or floats.  I'm not sure where you're getting a set() get() from.

    Here's a simple case to see the size or an Array vs a ByteArray.

    var a,s,e,m;
    s=System.getSystemStats().freeMemory;
    a=[0,0,0,0,0,0,0];
    e=System.getSystemStats().freeMemory;
    System.println(""+s+" "+e);
    m=s-e;
    System.println("A "+m);
    a=null;
    s=System.getSystemStats().freeMemory;
    a=[0,0,0,0,0,0,0]b;
    e=System.getSystemStats().freeMemory;
    System.println(""+s+" "+e);
    m=s-e;
    System.println("BA "+m);

    Here's the output:

    758344 758280
    A 64
    758344 758312
    BA 32

    With 7 elements, the ByteArray takes half.  The larger the array, the larger the savings.

    To assign values to the ByteArray, it's this simple

    a[4]=33;
    a[5]=-17;
    System.println(a);
    

    With the output being

    [0, 0, 0, 0, 33, 239, 0]

    as the numbers are unsigned by default, the -17 shows a 239

  • I think the confusion arises from the fact that the API documentation for ByteArray doesn't explicitly tell you how to access individual elements, except for this short blurb:

    ByteArray objects are fixed size, numerically indexed, single dimensional, and take Numbers with a value >= -128 and <= 255 as members.

    I think the docs could really use additional practical examples.

    Also, I think ByteArray is nice but it requires CIQ 3 or higher.

  • The Nordic samples in the SDK show the usage of ByteArray, as that's how you exchange data over BLE.

    For a new app, I can't think of the last time I targeted a pre CIQ 3 device,  I have a number of apps that run on CIQ 1 and CIQ 2 devices, but I also can't recall the last time I heard from a user with those devices.

    There are some older threads about how ByteArrays can be used to save a bunch of memory in things like watch faces that are tight on memory.

  • I'm not even sure if "fixed size" is true, considering the docs for add() says: "When adding a byte, the ByteArray size is increased and new bytes are inserted at the end"

    Anyway I tried to refactor from Array<Number> to ByteArray, and it's not worth in my case, it's adds 22 bytes to the code. The thing is that storing (lots of) DATA as ByteArray might save MEMORY, but in my case I only have 6 of them :) and the CODE to deal with it.

    Especially because util now I could do this: 

    heartRateZones = UserProfile.getHeartRateZones(currentSport);

    which now became:
    var hrz = UserProfile.getHeartRateZones(currentSport);
    heartRateZones = []b;
    heartRateZones.addAll(hrz);
     
    Even though in theory if I hold 6 32 bit Numbers in the memory it take 24 bytes, and if I hold 6 bytes it's 6 bytes, so the memory consumption should be 18 bytes less, it's still not worth it because of the 22 bye increase of code.
    So I'm reverting to Array<Number>
  • Let's see if anyone can come up with one with less bytes !

    A recent version of my post build optimizer added an optimization for initialized arrays. But I didn't consider the case where all the elements are set to the same value. So it currently ends up with 46 bytes for "heartRateZones = [0, 0, 0, 0, 0, 0] as Array<Number>;".

    If I specifically check for all the same values, and optimize that, I think it should get it down to 28 bytes if the value is a literal integer, or 25 bytes if it's in.a local variable (ie "zero"). [I'm not sure exactly what you're measuring. But I'm counting the size of the code to initialize the array; ie the increase between just doing "x = new [6];" and "x = <initialized array via some means>"]

    Meanwhile, I can shave 3 bytes off your solution by rewriting it as a do loop:

    heartRateZones = new Number[6];
    var i = zero;
    do {
      heartRateZones[i]=zero;
      i++;
    } while (i < 6);

    It saves 3 bytes because the for loop starts with a comparison and conditional branch, and ends with a goto back to the comparison. But the do loop puts the comparison and branch at the end, and avoids the goto (which is a 1 byte opcode, with a 2 byte offset). Ideally Garmin's compiler would do that for you in a case like this; but now that I've noticed it doesn't it should be fairly easy to do that optimization in either the source-to-source optimizer or the post build optimizer (or both, since there may be cases where one has more information than the other).