Number vs Float discrepancy between simulator and device

I’ve run into a weird issue and would like your opinions.

I have code that performs some calculations that should produce a Number, and then instantiates an object whose constructor expects a Number.

The compiler seems happy that these calculations result in a Number and allows me to pass the result into the constructor. Later, I store that value in a member typed as Object, and later convert it back to a Number again. At that point I had a safety instanceof check to confirm the Object really is a Number.

In the simulator everything works fine, but on some real devices (under some conditions) it looks like the calculation results in a Float. Monkey C “duck typing” then lets the Float propagate without complaint until my explicit check, which is how I noticed.

To me the core issue is that the compiler believes the code results in a Number, the simulator behaves accordingly, but real devices sometimes behave differently.

Here is the relevant code (with comments):

var minValue = sitemapNumeric.getMinValue(); // returns a Number
var maxValue = sitemapNumeric.getMaxValue(); // returns a Number
var step     = sitemapNumeric.getStep();     // returns a Number

var currentValue =
    numericItem.hasState()
    ? numericItem.getNumericState() // returns a Number
    : (minValue + Math.round((maxValue - minValue) / (2 * step)) * step).toNumber();

for (var i = minValue; i <= maxValue; i += step) {
    if (_currentIndex == -1 && currentValue <= i) {
        _currentIndex = _pickables.size();
        if (i != currentValue) {
            _nonConforming = new NumericPickable(currentValue, unit); // expects Number
            _pickables.add(_nonConforming);
        }
    }
    _pickables.add(new NumericPickable(i, unit)); // expects Number
}

And here is NumericPickable:

class NumericPickable extends CustomPickable {
    public function initialize(value as Number, unit as String) {

        // Workaround: force it to be a Number, so later reads are consistent
        value = value.toNumber();

        // CustomPickable stores the first parameter as Object
        CustomPickable.initialize(value, value.toString() + unit);
    }
}

Has anyone seen something like this before?

Once I understand what’s going on, the workaround is easy (the extra toNumber() in NumericPickable). But I’d really like to understand why the compiler and simulator treat this as a Number, while some real devices end up producing a Float.

If anyone is interested, here are the full source files. The first file contains the calculation discussed above, starting at line 39:

https://github.com/openhab/openhab-garmin/blob/main/source/user-interface/control-views/numeric/NumbericPickerFactory.mc

https://github.com/openhab/openhab-garmin/blob/main/source/user-interface/control-views/numeric/NumericPickable.mc