Is there a way to control variable types to manage memory use ?

The question pretty much covers it.

Is there some way to control what's an 8 bit quantity, what's a 16 or 32 bit quantity, etc ?

I have flags that only need to be true or false.

I have integers that could be represented in one byte, some in 2 bytes.

I have floats that don't need to be doubles.

Is there a way to control memory consumed by variables ??

I've done some hunting and I don't see it except for assigning constants which may be part of a solution but not the whole solution.

Any help would be much appreciated.

  • You can control what type (Number, Boolean, Float or Double) values are. (To write a double constant in Monkey C, use the d suffix). It's recommended to use floats in more case because doubles do take up more memory.

    You don't have access to types like 8-bit integer, 16-bit integer, etc in Monkey C (*). (Besides, due to structure alignment concerns, using integers with bit width smaller than 32 might only help when storing data in arrays.)

    - (*) You can use a ByteArray to store data in CIQ API Level >= 3.0.0

    - Another trick you can do is bit/byte-pack data yourself. Say you have a static array of data where the values are only between 0 and 255.

    e.g. instead of:

    var array = [ 1, 2, 3, 4, 5, 6, 7, 8, ... ];

    You can write:

    var array = [ 1 | (2 << 8) | (3 << 16) | (4 << 24), 5 | (6 << 8) | (7 << 16) | (8 << 24)

    I've successfully saved a lot of memory this way, but ofc the code that uses the data has to be written to decode it. And if the data is dynamic, you have to encode it yourself.

  • You can also use a ByteArray to deal with bytes.

    var ba=[0,1,2,3,4,..]b;

    with an integer array, like 

    var arr=[0,1,2,3,4,..]; 

    each Number is it's own object (but a simple object - same with floats or booleans)

    With a ByteArray, you have the functions encodeNumber() and decodeNumber()

  • Thanks, as mentioned above:

    - (*) You can use a ByteArray to store data in CIQ API Level >= 3.0.0

    So it won't work with older watches.

    I also don't think it would work if your source data is a JSON resource unless you load the resource and convert it (but then you'd have to have both the original data and the converted data in memory at the same time, while the conversion is happening). So in this case I think you'd want to byte-pack the source data yourself, unless your app has extra memory (at least at init time) to handle the memory spike during conversion.

  • FlowState,

    You say that the type used for values can be controlled. It sounds like that applies to constants only.

    Is there a way for me to calculate a value and ensure that the result is a float, not a double, and place that float into an array and not have it be stored as a double ?

    If I declare an array and put true / false values in the array, how much space does each true / false value occupy ? Maye I'll just experiment to find this out.

  • Is there a way for me to calculate a value and ensure that the result is a float, not a double, and place that float into an array and not have it be stored as a double ?

    Floating point values in Monkey C are floats by default. You won't get a double unless a value in your calculation is a double, or unless you explicitly convert to double.

    https://developer.garmin.com/connect-iq/api-docs/Toybox/Lang/Float.html

    Floats are 32-bit floating point values.

    By default, decimal values in Monkey C are Floats.

    If I declare an array and put true / false values in the array, how much space does each true / false value occupy ? Maye I'll just experiment to find this out.

    Without knowing any better I would say it's 4 bytes each, as I would guess that booleans are implemented via 32-bit ints

    As a matter of fact:

    var booleanArray = [ true, false, true]; // takes up 30 bytes

    var booleanArray2 = [ true, false ]; // takes up 25 bytes

    var booleanArray3 = [ true ]; // takes up 20 bytes

    var booleanArray4 = [ ]; // takes up 15 bytes

    (Same amount of space as similar arrays of Numbers).

    So I think it's:

    - 4 bytes for each underlying 32-bit integer

    - 1 byte for type field for each object

    - 15 bytes of overhead per array (arrays are expensive in monkey C -- if you have nested arrays, it can save a lot of memory to flatten them into a single array)

  • So if you want to efficiently encode boolean data in an array, you could either use a ByteArray for CIQ >= 3.0.0, or you could encode the data yourself by bit-packing 32-bit integers. In the latter case you could stuff 32 bools into 1 number, so it would be even better than using a ByteArray. Of course, you would might lose out on performance that way.

  • Np. Similar reasoning applies to Longs and Numbers btw. Number is the default integer type, and you're not going to get a Long out of a calculation unless the calculation involves a long or you explicitly convert to long. Pretty similar to how it works in C.

  • ByteArrays don't actually support booleans, just numbers between 0 and 255.  But you could use 0 and 1 for a boolean flag.

    If you set say -47 in a ByteArray, the sign isn't preserved, but when you use decodeNumber() and set the type to SINT8 to get -47 back.

  • ByteArrays don't actually support booleans, just numbers between 0 and 255.  But you could use 0 and 1 for a boolean flag.

    Yes, that's what I meant. That's why I said "encode boolean data" and not "store Boolean values". Of course, you could also bit-pack 8 booleans per byte in a byte array, too, and potentially save memory there (compared to an array of bit-packed Numbers which would waste 1 byte for every number, due to the 1-byte type field). But that would only work for CIQ >= 3.00.