I'm trying to get my app strict typing compliant. Already hit the wall with a simple array:
...
var showList = [0, 0, 0] as Lang.Array<Lang.Number>;
...
showList[0] = 4;
I'm trying to get my app strict typing compliant. Already hit the wall with a simple array:
The following compiles fine for me:
class abc { private var _flcDataSets as Array<Array> = new [6] as Array<Array>; private var _flcDataSet as Array<Number> = new [5] as Array<Number>; …
_displayString += (_data.FLdata[FL_temperature] as Number / 10.0).format("%.1f").toString() + "°C";
Couple of things here, not directly related to the problem.
You shouldn…
Seems safe but a little bit of overkill. You def don't want to cast v to a Number after you've determined it's not a Number, but in the given code it's harmless.
I would probably do something…
Off topic, but understand that multi dimension arrays are expensive in Monkey C.
Consider an array of arrays like
var a01 = [[v00,v01],[v10,v11],[v20,v21]];
that's 4 array object, and 6 value objects, and a new array each time you add something
Now this
var a0=[v00,v10,v20];
var a1=[v01,v11,v21];
That's 2 array objects and the same 6 value object (it's always 2 array objects)
and now,
v=[v00,v10,v20,v10,v11,v21];
The array is flat, and you need a bit of logic to use the bottom half or top half, but it's always one array object.
With a large amount of data, this will really make an impact
The logic also adds a few bytes, so it's worth to compare the code & data size when trying to optimize these kind of things
The logic also adds a few bytes, so it's worth to compare the code & data size when trying to optimize these kind of things
I agree, but in the case of Monkey C, nested arrays are so expensive that it's almost a slam dunk that flattening an array will save memory. (They're nothing like multi-dimensional arrays in C, for example.)
Thanks again for this useful hints. I now serialize my data and put it in a single Array of Number:
FLdata as Array<Number> = new [FL_tablesize] as Array<Number>;
case 3: // temperature displayString += (_data.FLdata[FL_temperature] as Float / 10.0).format("%.1f").toString() + "°C"; break;
Sounds to me like _data.FLdata[FL_temperature] is null in this case. You can verify that with System.println(_data.FLdata[FL_temperature]) just before the code crashes.
Just because you told the compiler that the value is a Float doesn't mean that it actually is. And I'm not sure why you declared the array as Array<Number> but you cast the value to Float. (You're allowed to divide a number by a float.)
Also, with regards to Array.add(), previously I said that it takes Object/null as an argument (according to the docs) but I found that in reality, it does type check the argument according to the type of the array. So I'm not sure how you could've added null unless you did an explicit cast such as _data.FLdata.add(foo as Number), where foo was null.
Where does the array data come from? Do you have code you can share?
"as Float" doesn't convert a Number to Float. ".toFloat()" does.
_data.FLdata[FL_temperature] can be either Number or Null, that's why when you use "as Float" it thinks it can be either Float or Null.
You'll need IMHO:
(_data.FLdata[FL_temperature] as Number).toFloat()
But probably even this is enough:
(_data.FLdata[FL_temperature] as Number) / 10.0
because when you do arithmetich between Float and Number then it should become a Float
"as Float" doesn't convert a Number to Float. ".toFloat()" does.
Exactly. "as" isn't a C-style cast (the value is not coerced to a different type), all it does is change the compiler's idea of what the type is at compile-time, for the purposes of type checking.
However, there's no need to call toFloat() in this case, as the result of dividing a Number by a Float will be a Float.
except that the array items can be Null
_data.FLdata[FL_temperature] can be either Number or Null, that's why when you use "as Float" it thinks it can be either Float or Null.
Incorrect. Runtime type checking and compile-time type checking are completely separate.
First of all, "as Float" tells the compiler that the value is a Float (not Float or null).
2nd, the given exception (UnexpectedTypeException: Expected Number/Float/Long/Double, given null/Float) is actually saying that the value was null at runtime (nothing to do with Monkey C type checking, which is static analysis at compile time.)
TL;DR Monkey Types (with "as") are checked solely at compile time. Runtime type exceptions are based on the true (duck-typed) type of the object. (That's why even "simple objects" -- which are similar to primitives -- take 6 bytes and not 4, because every object, even a Number or Float, has an associated runtime type.)
As a simple example, the following code will compile but crash at runtime.
var x = null as Number; //whoops
var y = x / 42;
// Exception: UnexpectedTypeException: Expected Number/Float/Long/Double, given null/Number
The explanation is that the compile-time cast of null to Number "tricks" the compiler into thinking the division is ok, but runtime type checking causes the exception to be thrown. Without "as Number", the code will fail to compile due to compile-time type checking.
This highlights a huge problem with explicit casts using "as" -- there's no protection against nonsensical casts that can break your app. Contrast with typescript, which prevents explicit casts between incompatible types, unless you cast to any first.
except that the array items can be Null
I've explained in my comment below yours why your reasoning is incorrect.
1) The explicit cast to Float (using "as") tells the compiler that the given array item is Float (not Float or null)
2) The explicit cast (as well as any Monkey Type stuff) only affects compile-time type checking but the runtime type check (and the given exception) comes from the fact that the array item is actually null at runtime.
Your assertion that the exception happened because the compiler "thinks" the value can be Float or null is just wrong. The exception happened because the value *was* null, independent of any compile-time cast using "as". I can see where'd you get that idea, given the weird and confusing "null/Float" wording in the exception.
Compile-time type checking != runtime type checking.
Also, x.toFloat(), where x is null, would produce a runtime error in any case, if that's what you meant.
If the array members can be null, then:
- the type definition of the array should reflect that
- there should be logic to avoid dividing null by a float.