WARNING: Cannot determine if container access is using container type

Hello brains trust,

Need some help please.  I receive the compiler warning "Cannot determine if container access is using container type" when using STRICT type checking on the following excerpt of code.  Mind you, the code still runs.

BUT, I can't figure out how to eliminate the warning (it's messing with my OCD).  What am I missing?

function test() as Void {
	var w = null, ti, sz = 6;

	w = Weather.getHourlyForecast();
	if (w != null) {
		for (var j=0; j<sz; j++) {
			ti = Gregorian.info((w[j].forecastTime as Moment), (Time.FORMAT_LONG as DateFormat));
		    // ... more code follows, but irrelevant for this illustration
		}
	}	

}	

  • Sigh....  Worked it out.... umb-da.

    Key change:

    w = Weather.getHourlyForecast() as Array<HourlyForecast>;

    function test() as Void{
    	var w, ti, sz = 6;
    
    	w = Weather.getHourlyForecast() as Array<HourlyForecast>;
    	if (w != null) {
    		for (var j=0; j<sz; j++) {
    			ti = Gregorian.info(w[j].forecastTime as Moment, (Time.FORMAT_LONG as DateFormat));
    		}
    	}	
    
    }	
    

  • I have the exact same warnings in my compiler. On code like this (this is an onreceive callback from a webrequest):

        function onReceiveRooms(responseCode as Lang.Number, data as Lang.Dictionary or Lang.String or Null) as Void {
       		Log("onReceive responseCode="+responseCode+" data="+data);
           // Check responsecode
           if (responseCode==200)
           {
           		// Make sure no error is shown
               	// ShowError=false;
               	if (data instanceof Dictionary) {
    				if (data["status"].equals("OK")) {
    	            	if (data["title"].equals("getplans")) {
    						if (data["result"]!=null) {
                                Log("Getting the rooms");
    							roomItems={};
    							for (var i=0;i<data["result"].size();i++) {
    								roomItems.put(data["result"][i]["idx"], new WatchUi.MenuItem(data["result"][i]["Name"], null, data["result"][i]["idx"],{}));
    

    The warning is triggered by the last line. Can anyone tell me how to fix?
  • The compiler doesn't know what type is data["result"], data["result"][i]

    You can tell it using "as"

  • And what would that look like in coding?

  • I don't know, it's your data... You can try something like:

    in the function declaration:

    data as Lang.Dictionary<String, Array<Dictionary<String, String or Number>>> or Lang.String or Null

    If that doesn't work then you can also do it here, but it's uglier:
    roomItems.put(((data["result"] as Array)[i] as Dictionary)["idx"], ... ;

    also see: forums.garmin.com/.../the-road-to-strict-typing-is-paved-with-good-intentions

  • The error tells you what it''s looking for. Copy/paste it into a typedef and use that. It will change with SDK versions, so it will be easier to maintain this way too.

    //do this up top
    //typedef webData as Null or $.Toybox.Lang.Dictionary or $.Toybox.Lang.String; // SDK 6.2
    typedef webData as Null or $.Toybox.Lang.Dictionary or $.Toybox.Lang.String or $.Toybox.PersistedContent.Iterator; // SDK 6.4+
    // then in the function
    public function onReceiveNearest(response as Number, data as webData) as Void {

  • I don't think that will change anything. He already has Dictionary in the function declaration. The error is not from there, it's where he's indexing the dictionary and it's sub structures, because it doesn't know what type is data["result"], ...

  • For the elements assign them to their own variable and type it at that point. The compiler doesn't seem to handle nested array and dictionary elements very well.

    var rooms = data["results"] as Array<String or Number or Array<Float> >; // or whatever the type is
    

    Then use the variable instead of the top level element. It will be faster and use less memory, too. Keep doing this for each level you need to drill down to so in your for loop you should have something like:

    var room = rooms[i] as < whatever this type is>;
    

    Then use the room["idx"] in your put statement.

  • data is a json object (converted to monkey c by monkey c itself). I cannot change the definition because it's declared in the OnReceive callback method and then i get other errors.

    However with a little workaround by declaring another var it worked (bit strange to include extra vars to supress typecheck warnings, but hey if it works it works):

    function onReceiveAllDevices(responseCode as Lang.Number, _data as Lang.Dictionary or Lang.String or Null) as Void {
           var data=_data as Lang.Dictionary<Lang.String,Lang.Array<Lang.Dictionary>>;
     
    Only weird thing is: This works on all lines of code with data["result"][index]["field"] except this line:
    devicedata=Levels[data["result"][i]["LevelInt"]];
    only weird thing is that the lines directly below it:
    if (data["result"][i]["LevelInt"]>0) {
      enabled=true;
    }
    (so the devicedata= gives the warning, but the  (data["result"][i]["LevelInt"]>0 ) does not!
  • 'cause the problem is the Levels[...]