long type vs. number

Did not program for some years - so I tried to understand the (speed and memory) differences between variables (global, local, hidden, public) and their types (long vs. number)...

Interestingly I was not able to assign a larger value to a long variable directly, for example the code var l=2147483647.toLong(); l=2147483648; is not allowed. Is there a workaround?

Also didn't find if calculating with numbers or long variables do have an impact in memory or execution speed - did anyone made some more tests here?


	function onUpdate(dc) as Void
	{
		var l=2147483647.toLong();		// 8 byte (-9223372036854775808 to 9223372036854775807)
		var n=2147483647.toNumber();	// 4 byte (-2147483648 to 2147483647)
		
		l=l<<16+65535;
		l=l<<16+65535;
		
		for(var i = 0; i<8; i++)
		{
			dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_TRANSPARENT);
			dc.drawText(120,    i*30,Graphics.FONT_SMALL,l,Graphics.TEXT_JUSTIFY_LEFT);
			dc.drawText(120,300+i*30,Graphics.FONT_SMALL,n,Graphics.TEXT_JUSTIFY_LEFT);
			l=l+1;
			n=n+1;
		}
	}


Top Replies

All Replies

  • Don't you want to use var l = 2147483647l; to make it a long?

  • Number is 32 bit signed integer, long is 64 bit. But there's an additional memory price for using long if I understand correctly, because it's an object while Number is a primitive

  • Interestingly I was not able to assign a larger value to a long variable directly, for example the code var l=2147483647.toLong(); l=2147483648; is not allowed. Is there a workaround?

    Local variables don't have fixed types in Monkey C, so the fact that you previously assigned a long to the l variable has no bearing on the subsequent assignment.

    Besides, as gasteropod pointed out, you need the l suffix to create a long numeric literal. 2147483648 by itself is invalid and should produce a compiler warning or error.

    var x = 2147483647; // x is a Number
    x = 2147483647l; // x is now a Long
    x = 2147483648l; // x is still a Long
    x = 2147483648; // compiler error: "The literal '2147483648' of type '$.Toybox.Lang.Number' is out of range."

    Although technically, Monkey C doesn't have primitive types (according to the docs - their rationale is that every type is an object), it does have types that can be considered primitives (also according to the docs - no, it's not consistent.)

    The way I like to think about it is the primitive types in Monkey C are the ones which are passed by value and are immutable, as opposed to other types, which are passed by reference and are mutable.

    What I mean by "passed by value and immutable" [*]:

    var y = 5; 
    var z = y; // z receives a copy of y (pass by value)
    y = 10; // this doesn't change the original Number (5), it assigns a new Number (10) to y (Number is immutable)
    System.println(z); // z is still 5, because z received a copy of y, not a reference

    These "primitives" also happen to have much less overhead than other types of objects (non-primitive objects which are not array or dictionaries have an overhead of about 80 bytes, even for an empty object with no fields or functions other than what's inherited from Object).

    From this POV, the following Monkey C types are primitives:

    Number, Long, Float, Double, String, Null, Boolean

    However, not all of these primitives have the same properties when it comes to memory usage. Only the "small" primitives whose value fits into 32 bits are allocated on the heap. "Big" primitives and other objects are allocated on the stack.

    "Small" primitives (1 byte for type + 4 bytes for value = 5 bytes): Number, Float, Null, Boolean

    "Big" primitives (1 byte for type + 4 bytes for stack reference + X bytes for value = 5 + X bytes): Long, Double, String

    From a practical POV, if you have an array of numeric values, it's best to use Number or Float unless you absolutely need Long or Double.

    An array of Numbers will be 5 bytes per element plus about 13 bytes for the overhead of the Array object itself. An array of Longs will be at least 13 bytes per element (1 byte for type, 4 bytes for reference, 8 bytes for value) plus 13 bytes of overhead for the array itself. 

    When you have 100s or 1000s of array elements, the memory costs add up. (In fact, a ByteArray is the most efficient way to store large amounts of bytes - each 1-byte element only takes 1 byte in the array, as opposed to an array of Numbers, where each 4-byte element takes 5 bytes in the array.)

    [*] On the flip side, Array and Dictionary types are passed by reference and mutable (although they do have less overhead than other objects). For example, the overhead for an Array is about 13 bytes, while the overhead for objects other than Number, Long, Float, Double, String, Null, Boolean, Array or Dictionary is about 80 bytes.

    e.g.

    var a = new [5]; // create empty array of 5 elements (initialized to nulls)
    var b = a; // b now points to the same Array as a (pass by reference)
    a[0] = 1; // the original array is modified (Arrays are mutable)
    System.println(b[0]); // prints "1" because a and b point to the same array

  • Thank you all for your helpful responses, doing a good job for my tiny tools I am creating now for my forerunner and edge computer (which will be more difficult because the garmin ant+ stick does not work on my notebook - but this is another story).

    I've adopted my datafield now and changed all Long variables to Numbers - hopefully this will squeeze the used memory a little bit or helps to use a little bit less battery Slight smile

    BTW does anyone know how to check the variable type? Something like isNumber() does not exist but would be helpful. In the following example y does change its type from number to long...

    var x = (1l<<62-1)<<1+1; // long
    var y = 5; // number
    y
    =x;  // y is now long

  • BTW does anyone know how to check the variable type? Something like isNumber() does not exist but would be helpful

    instanceof

    if(a instanceof Number) {