How to use build exclusions on certain functions?

Hi all, I just attended the GDVC breakout session about optimal Monkey C. Thank you, Garmin for adding the option to type check! I think type checking can help me find code I'm not using and get rid of it. When I turn type checking on though, I get errors about undefined symbols for this code (simplified). Would you all mind taking a look and giving me tips on how I can get this to work?

//...
if (id == :item_15) { 
    // this menu option only pops up if routing is enabled for the device. 
    // But the compiler doesn't know that, and when I run a device that
    // doesn't support routing, I get this error:
    // Undefined symbol ':request_directions_to_pin' detected.
    request_directions_to_pin();
} else if (id == :item_16) {
    do_other_things();
}
//...


(:routing)
function request_directions_to_pin() {
    // do stuff
}
Thanks!

Top Replies

All Replies

  • One approach is to have a pair of exclusions for every feature you want to "conditionally compile" in this manner, which can get annoying to maintain in your jungle file, as you can imagine.

    It can help to define a default set of exclusions, and explicitly assign other sets of exclusions to devices which are the exception to the rule.

    e.g. Let's pretend out of all the devices you build for, only FR 955 supports routing and hrv. (I'm making up a new feature for your app for the purposes of this example)

    monkey.jungle:

    # The following exclude annotations are applied by default
    base.excludeAnnotations = routing;hrv

    # List all the exceptions to the default rule here
    fr955.excludeAnnotations = no_routing;no_hrv

    # ...

    app source:

    (:routing)
    function request_directions_to_pin() {
        // do stuff
        // ...
    }

    (:no_routing)
    function request_directions_to_pin() { }

    (:hrv)
    function get_hrv_sensor_data() {
        // get data
          // ...
        return data;
    }

    (:no_hrv)
    function get_hrv_sensor_data() { return null; }

    You'll notice that if memory is a concern here, your empty functions and the code that calls them still take up memory in the form of code. It's not much, but it can be an issue for data fields on older devices or even current devices such as vivoactive 4.

  • I think what you are confusing optimization and type checking.  Try optimization without type checking.  The two were a bit intermixed for me at the GDVC, where type checking could help optimization but they aren't the same

  • I think what you are confusing optimization and type checking. 

    While that's true (I mentioned it in an earlier edit but decided it took away from the main point), it doesn't change the fact that:

    1) Type checking actually caught an error in OP's code (which is a good thing), namely that request_directions_to_pin() is not defined in all builds, but it is called for all builds

    2) OP needs a way to get around that error (by having an empty definition of request_directions_to_pin() in the builds where it doesn't currently exist, for example.)

    Try optimization without type checking

    In this specific case, that will simply change the observed compile-time error to a run-time error

  • In this specific case, that will simply change the observed compile-time error to a run-time error

    Will it?  That's where turning off type checked can verify if type checking is flagging something but the app still runs fine.  Then it's a matter figuring out how to make type checking happy.

  • Will it? 

    You're right, it won't crash at runtime. Sorry, my bad, wasn't thinking.

    Then it's a matter figuring out how to make type checking happy.

    Just my opinion, but this is the wrong way to look at things in general. Type checking isn't a bunch of annoying hoops that devs are forced to jump through "to make type checking happy". It's supposed to help you write better code. Related: I don't really like Garmin's implementation of type checking, which forces people to do a lot of explicit casts to make the type checker happy. That actually helps you write worse code, since explicit casts are unsafe (especially the way Garmin implements them.) I also dislike the design where type declarations and type casts both use the "as" keyword, since they're on the opposite ends of the spectrum when it comes to safety. There should be a clear distinction between the two things, IMO.

    It's too bad that in cases like this, the type checker really is forcing to devs to jump through hoops to make it happy.

  • That's also why there are different levels of type checking.  -l3 might be a bit too harsh for some apps, but -l1 and -l2 might be fine.

    One thing that was mentioned at the GDVC yesterday is that at some point controlling type checking will be allowed in jungles so in some old/legacy apps you'll be able to turn it off,  but use different levels in different apps or be device specific for other apps..

  • One thing that was mentioned at the GDVC yesterday is that at some point controlling type checking will be allowed in jungles so in some old/legacy apps you'll be able to turn it off,  but use different levels in different apps or be device specific for other apps..

    Interesting, thanks. I think this is a feature wanted to see.

  • I know it's been requested since type checking was first introduced by people that have apps written long ago and only want type checking for new apps, for example.. Not much was said about it yesterday so we will see.

  • Yeah, they told us yesterday that some features can be put in the jungle file. Which is pretty cool. But it was who started this. In which I added that much more can be lifted to the jungle file.

    See https://forums.garmin.com/developer/connect-iq/i/bug-reports/feature-request-allow-to-spedify-type-checking-level-in-the-monkey-jungle-file for more on this.

  • Thank you all for your replies! Using pairs of build exclusions was not as hard as I had envisioned it, and so I was able to quickly implement them.

    Thanks for your help!