Value 'onSettingsChanged' not available in all function scopes.

I have a datafield. I am trying to add a background process to download some json file from the web. (I know new devices can do it in the foreground, but I also want it to work for older devices).

So I added (:background) annotation to the class of MyApp:

import Toybox.Application;
import Toybox.Lang;
import Toybox.WatchUi;

(:background)
class MyApp extends Application.AppBase {
    hidden var view as MyView?;

    function initialize() {
        AppBase.initialize();
    }

    (:typecheck(false))
    function getInitialView() as Array<Views or InputDelegates>? {
        self.view = new MyView();
        return [ self.view ] as Array<Views or InputDelegates>;
    }

    (:foreground)
    function onSettingsChanged() as Void {
        if (view != null && !isRunningInBackground()) {
            view.onSettingsChanged(SETTINGS_CHANGED_FROM_CONNECT_IQ);
        }
    }
}

(:no_ciq_2_4_0, :background)
function isRunningInBackground() as Boolean {
    try {
        var app = getApp();
        app.setProperty(PROPERTY_NON_EXSISTANT, 1);
        app.deleteProperty(PROPERTY_NON_EXSISTANT);
        return false;
    } catch (ex) {
        return true;
    }
}
(:ciq_2_4_0, :background)
function isRunningInBackground() as Boolean {
    try {
        Properties.setValue(PROPERTY_EXSISTANT, false);
        return false;
    } catch (ex) {
        return true;
    }
}

Until now in onSettingsChanged it called view.onSettingsChanged which was always set (IMHO), but now when the background app will run there won't be a view obviously.

The (:foreground) annotation doesn't help, I guess the whole class is in the background code, so if the onSettingsChanged method is overridden then it calls it. I get the following compilation errors. How can I make this compile?

ERROR: fr955: MyApp.mc:68,12: Value 'onSettingsChanged' not available in all function scopes.
ERROR: fr955: MyApp.mc:68,12: Cannot find symbol ':onSettingsChanged' on type 'Null'.
ERROR: fr955: MyApp.mc:68,12: Value 'SETTINGS_CHANGED_FROM_CONNECT_IQ' not available in all function scopes.

The 2nd error is just a bug in the compiler, as it should know that view isn't null, but what can I do if I don't want this code to run at all if the background?

Top Replies

All Replies

  • You always advise people to turn off type checking if they run into compile-time errors (which may or may not be related to type checking.)

    Well, I developed stable production apps years before type checking, If you understand CIQ, what does it buy you?

  • I guess your onSettingsChanged works because it only calls code that itself is (explicitly or implicitly) annotated as :background. I haven't try this, but I'm pretty sure that if I added (:background) on MyView class, then it would work

    In onSettingsChanged() I'm calling methods from MyApp class (which is annotated with :background like your's) and _myView.onSettingsChanged() method.

    _myView is a private field inside the MyApp class (similar to your's) and MyView class is not annotated with :background. I suppose, its methods are available in background because _myView is a private member of background-scoped MyApp class.

    What else looks different than my code is a combined annotation (:ciq_2_4_0, :background). What if you replace it with just (:background)?

    I have no trust to combined annotations in CIQ since the time I tried it for barrels exclusion and it didn't work as it was supposed, so it may be worth to check

  • This is a DF I made a month ago. Now I'm trying to add a background app to it to download a JSON file from the web. The existing DF has the onSettingsChanged and it updates the screen (that's why it calls a function in the view). Obviously I don't want to remove this feature now, but still want to be able to add the background stuff

  • I use combine excludeAnnotations without problems. However your comment made me think how :background works. Maybe it's a bit different from regular excludeAnnotations... I'll give it a try

  • You always advise people to turn off type checking if they run into compile-time errors (which may or may not be related to type checking.)

    Well, I developed stable production apps years before type checking, If you understand CIQ, what does it buy you?

    It's always all about you. I wonder why Microsoft created typescript (type checking for javascript) and the python maintainers added type checking to python.

    Not everyone can be a godlike coder like you. Just 13 hours ago someone posted a question about a bug that could've been avoided if type checking was set to a certain level. Ofc you would prefer that the type checker didn't exist so that you can be the primary and sole source of knowledge for all things CIQ.

    Anyway, the point you may have missed is that I don't think all of errors in the OP are related to type checking, and in the past you've suggested turning off type checking to address errors that were clearly not related to the type checker.

    It's just a funny knee jerk reaction to me. And I think it does more harm than good bc you're suggesting turning off a valuable tool for ensuring program correctness as a first resort when anything goes wrong.

    EDIT: Well, looks like my own knee jerk reaction was wrong haha

  • Both background and glance annotations are different than user annotations, as they control the order of things in the prg file.

    in a prg file, there is a header, then the code with the background annotation, then the code with the glance annotation, and then the rest.  This is how CIQ handles the smaller amount of memory for backgrounds and glances, as with the prg set up this way so only the first part gets loaded for the background or glance

  • Anyway, the point you may have missed is that I don't think all of errors in the OP are related to type checking, and in the past you've suggested turning off type checking to address errors that were clearly not related to the type checker.

    It's just a funny knee jerk reaction to me. And I think it does more harm than good bc you're suggesting turning off a valuable tool for ensuring program correctness as a first resort when anything goes wrong.

    Turning off type checking as a test is a good way to see when/where the warning/error is being flagged.  

  • Actually it turns out it is a typechecker bug. It does compile with project.typecheck={0,1,2} but fails with 3.

    Opened bug report: forums.garmin.com/.../bug-strict-type-checker-fails-to-compile-code-that-checks-existence-of-function-using-has

  • Turning off type checking as a test is a good way to see when/where the warning/error is being flagged.  

    Fair, and you were absolutely right.

    Actually it turns out it is a typechecker bug. It does compile with project.typecheck={0,1,2} but fails with 3.

    Haha I deserved that. Thanks for confirming that.

    Note that getInitialView() will also fail to compile for the same reason (even if the return type was changed to match the new format), if the annotation that suppresses type checking is removed. (I realize you wouldn't do that in your case because you want to preserve compatibility with old SDKs.)

    For example, if I try to build the following code for a datafield in SDK 7.1.1...

    function getInitialView() as [Views] or [Views, InputDelegates] {
       return [ new BgFieldView() ];
    }

    ...I get the following errors on the indicated line:

    ERROR: ...  Value 'BgFieldView' not available in all function scopes.
    ERROR: ... Value 'initialize' not available in all function scopes.

    The fix I suggested earlier doesn't work (moving the implementation to a global function and using a has check for the symbol), for the same reason that the original bug happens: because the type checker sees a function in the AppBase-derived class that exists in both BG and FG (such as getInitialView or onSettingsChanged), but gets mad because the function refers to something that only exists in the background.

    It seems that CIQ really could use a working foreground annotation to get around this kind of problem, where a class is marked as background, but some of its members are not needed or should not be present in the foreground. (It would also save some memory in background processes.)

    EDIT: Or a "not_background" annotation. ("foreground" would be problematic since things that are marked as glance and background are also present in the foreground.)

  • for other devs who get here: the somewhat working solution is to annotate methods like getInitialView with: (:typecheck(disableBackgroundCheck)) though this still doesn't fix the onSettingsChanged, because there's the null check that somehow gets screwed up in the compiler, so there  (:typecheck(false)) is needed until Garmin fix these issues.