Acknowledged
CIQQA-3064

Compiler warns about deprecated symbol even when building for device where symbol is not deprecated

e.g.


// in entry point class that extends appbase

var val;
if (Toybox.Application has :Properties) {
// ciq >= 2.4.0
  val = Application.Properties.getValue("foo");
} else {
// ciq < 2.4.0
  val = AppBase.getProperty("foo"); // compiler warns that AppBase.getProperty is deprecated
}

Regardless of what device this code is built for, the compiler will warn that AppBase.getProperty is deprecated. I would argue this is confusing and misleading because:

1) getProperty is not deprecated for devices with CIQ < 2.4.0. In fact, for those devices getProperty is *required*, if you want to read persisted data

2) Even for devices with CIQ >= 2.4.0, the warning may be confusing because it still implies that your code is wrong because it calls that function (even though as written, it will never be called for those devices.)

Here's an example of where the deprecation warning may have led to confusion (or not, it's hard to say):

(it's a deprecation warning triggered by an SDK sample which correctly shows code which can run on both older devices and newer devices, using old deprecated enums for older devices, and new non-deprecated enums for newer devices)

https://forums.garmin.com/developer/connect-iq/i/bug-reports/bug-documentation-typos-in-toybox-position-enablelocationevents-example

Nonetheless, the issue of the deprecation warnings has come up many times in the forums.

I realize this is sort of a no-win situation here. I don't have any good suggestions for fixing it. But I do think there needs to be a way for the compiler to convey that code which uses deprecated symbols *may* be correct after all.

  •  I realize that Monkey C implements has checks, but the limitation here is that the compiler won't do things like decide that if your call is wrapped in has checks, then it won't warn about deprecation. Ofc arguably this is the wrong thing to do, since it would only encourage devs targetting newer CIQ versions to use deprecated functions like AppBase.getProperty[] forever - which has happened anyway. I would argue that without having some kind of compile-time / run-time branch based on CIQ *version*, then the optimal behaviour for both devs and the CIQ team will never be implemented.

    In other words, if the compiler sees the following code, there's no way for it to know that the dev only intends for it to run on devices with CIQ < 2.4.0:

    if (!(Toybox.Application has :Properties) { 
    // ciq < 2.4.0
      val = AppBase.getProperty("foo"); // compiler warns that AppBase.getProperty is deprecated
    }

    That's obviously why the compiler warning is unconditional.

    For example, CIQ had a feature like if #available, devs could write code like this:

    if #available(ciq_2.4.0) {
      // use Application.Properties()
    } else {
      // use AppBase.getProperty()
    }

    Here the intent is explicit and the version availability check excludes the possibility of using AppBase.getProperty() on a platform for which it is deprecated. AppBase.getProperty() will only be used for CIQ < 2.4.0, where it is *not* deprecated, so there's no reason for the compiler to raise a deprecation warning.

    As a matter of fact, if this version check feature were available, the compiler could be even stricter and raise an *error* if certain deprecated functions are used without a version check.

  • More details:

    This is never going to happen, but it would be great if the Monkey C compiler supported conditional compilation / runtime checks based on literal CIQ API level, in such a way that the compiler understands what version is being targeted. Simply getting the CIQ version at runtime via an API call is not sufficient - it has to be a construct that the compiler understands and controls, so that it can make decisions based on which version is being targeted. This goes beyond minApiLevel, as it would allow for different code to be include / excluded or executed / not executed based on *differing* CIQ API level amongst app targets.

    Not to be an Apple fanboy, but let's say your iOS app targets devices iOS 16, 17, and 18. If you call a function which is available starting in iOS 18, then the compiler *forces* you to add a runtime check along the lines of "if @available[ios18]" around the code. This enforces both the desired source code documentation and runtime behaviour: the code in question only runs on ios 18, so it's impossible for it to crash on ios 16 or 17 because it won't run. Apple implements both compile-time macros - if #available - and runtime checks - if @available - to select different code based on platform version.

  • TL;DR CIQ needs compiler constructs like Apple's if #available [conditional code at compile-time, based on API level] and if @available [conditional code at run-time, based on API level, at a level that the compiler controls and understands.]

    I feel like Garmin isn't too interested in supporting such old devices though

  • Thanks for documenting it on the forums - ran into the same issue after painstakingly making sure that only old devices use the old API... Glad to know it's a known issue and that the approach I took (excludeAnnotations) _is_ working.