Type Check Level: strict causes Cannot find symbol ':data' on type 'Null'

Wen I set the Type Check Level to strinct then the following code doesn't compile:

if (sensor != null && sensor.data != null) {...}

Type Check Level: strict causes Cannot find symbol ':data' on type 'Null'

How am I supposed to deal with these? Is there a better solution than the too verbose casting:

if (sensor != null && (sensor as Sensor).data != null) {...}

The compiler must be clever enough to figure it out that sensor can't be null there, or at least we should have the ! operator like in kotlin:

if (sensor != null && sensor!.data != null) {...}

  • I know, you're the perfect programmer, but I'm not...

    Garmin: "Hey everyone, we released [HELPFUL FEATURE]. Hope this helps! :D"

    Forum member: "[HELPFUL FEATURE] has a bug :("

    Other forum member: "No worries, I don't use [HELPFUL FEATURE]. Thumbsup"

  • I'd use -l1 and -l2 before -l3, as 1 and 2 could be helpful.  3 just seems it causes confusion and might not really be that helpful.    I'd rather worry about my app than -l3 type checking bugs.

  • I understand the practical need to work around bugs in the dev system, but it feels like the type checking system should work 100%, if Garmin wants devs to use it. L2 and L3 give the dev more information than the other levels, but clearly there's some outstanding issues.

    I think the idea is that using the type checking system will produce more robust apps, so the fact that it rejects valid code seems like a problem to me.

    For example, at work I use TypeScript quite a bit, and we can't push code unless there are 0 type errors or lint warnings/errors. (In some very rare cases, we may need to opt-out of type checking for a given line of source code.) On an earlier project at the same company, we used javascript heavily (which lacks compile-time type checking). One of our most frequent run-time errors was failing to check a function's return value for "undefined" (which is similar to null) -- this is the kind of thing that could be totally avoided with strict type checking.

  •  If you meant the 4.1.4 Compiler 2 Beta, then this is still not fixed as far as I can see. Or at least some version of it:

    (:black_and_white)
    const ZONE_COLORS as Array<Graphics.ColorType> = null;
    (:color)
    const ZONE_COLORS = [-1 /*COLOR_TRANSPARENT*/, 0xAAAAAA /*COLOR_LT_GRAY*/, 0x00AAFF /*COLOR_BLUE*/, 0x00FF00 /*COLOR_GREEN*/,
            0xFF5500 /*COLOR_ORANGE*/, 0xFF0000 /*COLOR_RED*/, 0xAA0000 /*COLOR_DK_RED*/] as Array<Graphics.ColorType>;
    
    function foo(i as Number) {
        if (ZONE_COLORS != null) {
            var c = ZONE_COLORS[i]; // Attempting to perform container access on null.
        }
    }

    When I try to compile it with the 4.1.4 Compiler 2 Beta with -l 3 (as I did with the old compiler) and with the following relevant annotations:

    instinct2.excludeAnnotations = base;no_api1_3;no_api2;memory16K;color

    then I get the error: Attempting to perform container access on null.

    What's worth to note that this compiled with 4.1.4 compiler.
    Actually it comiled with this line of code:
    (:black_and_whiteconst ZONE_COLORS as Array<Graphics.ColorType>;
    aka without the =null, but then I geth this with the Beta compiler:
    Member 'ZONE_COLORS' not initialized but does not accept Null.
  • I did mean the Compiler 2 Beta, but I couldn't be specific about it at the time because I wasn't sure when it would be going out. (And, I didn't want to spoil the surprise!)

    I'll get this reported for further investigation. Thanks for the follow up!

  • the simple case works now though:
    if (foo != null && (foo as String).length()>0)
    can be now written as:
    if (foo != null && foo.length()>0)
    Which is already a positive step, but if we could eliminate all the repeated (foo as <Type>) from all the code block after the if, that would be even nicer:

    if (foo != null) {
       var x = foo.substring(0,3);
    }


    if (are != null) {
        var item = arr[i];
    }

  • Member 'ZONE_COLORS' not initialized but does not accept Null

    I think this may be the clue. The type checker doesn't try to dynamically track the types of globals/members (according to the documentation) because they could change (eg as a result of a function call). I've seen cases where it *does* track them briefly, but it seems to be inconsistent about when it does (obviously, this case would be safe, for example).

    Your example would work if you assigned ZONE_COLORS to a local, then checked, and used the local. It might even produce smaller code. I'm pretty sure it would produce smaller code if there were 3 or more uses of ZONE_COLORS in foo.

  • There are only 2 uses :) and the 1st one is the check if it's null. This code is not ideal for my app (it would be better to refactr it 'cause this part of the code has only meaning for devices with color screen, so it could be excluded totally. But bad code is always good code for testing the compiler features/bugs ;)

  • There are only 2 uses :)

    Well, I just tested it, and even with just the two uses (ie an exact copy of your code above), its two bytes smaller with the local.

  • you mean instead of 
    class X {
       const ZONE_COLORS = [];

    using:
    class X {
       private var ZONE_COLORS = [];



    Or keep the const and copy it to a local var in the function I use it? I doubt this will decrease code since it'll add a new local variable.