Complete
over 6 years ago

Bogus Circular Dependency error

I am getting a bogus circular depency error. My app has a dependency on my barrel. The code of my barrel is shown below. My barrel has a global variable initialized to an instance of InitClass, which triggers the execution of the corresponding constructor when the module is first loaded. This constructor registers a sensorData listener callback. The call to Sensor.registerSensorDataListener() is what is causing the circular dependency error. This seems to be a problem with referencing that particular method and not the entire Sensor module. I know this because if I replace the call to Sensor.registerSensorDataListener() with the following line of code

    System.println(Sensor.SENSOR_BIKEPOWER);

Then the code compiles fine and I do not get the circular dependency error. What I think may be happening is that the system is treating the "options" parameter as dependency that the Sensor module is having on my barrel, which is clearly incorrect. 

module MyBarrel
{
    (:MySubModule)

    module MySubModule
    {
        using Toybox.Sensor;

        var options = {
            :period => 1,
            :accelerometer => {
                :enabled => true,
                :sampleRate => 25,
                :includePitch => true
            },
            :heartBeatIntervals => {
                :enabled => false
            }
        };

        var init = new InitClass();

        class InitClass
        {
            function initialize()
            {
                Sensor.registerSensorDataListener(method(:callback), options);
            }

            function callback(sensorData)
            {
            }
        }
    }
}

Former Member
Former Member
  • I don't think this is a bogus error. The cycle detection code detects actual cycles, not possible cycles.

    The parameter passed to `registerSensorDataListener` is a `Lang.Method` which keeps a reference to an object and a function to call on that object. That means the Sensor module has a reference to the `MyBarrel.MySubModule.init` object. I'm not sure where the other references are, but they are there.

    The easiest way to avoid something like this is to add methods to your module to register/unregister callbacks. Something like this:

    module MyModule
    {
        function registerSensorDataListener() {
            var options = {};
            
            //...
            
            Sensor.registerSensorDataListener(method(:onSensorDataCallback), options);
        }
        
        function unregisterSensorDataListener() {
            Sensor.unregisterSensorDataListener();
        }
        
        function onSensorDataCallback() {
        }
    }

    It will require that the module/barrel user call `registerSensorDataListener` and `unregisterSensorDataListener` (typically from `App.onStart` and App.onStop` or `View.onShow` and `View.onHide`), but it should eliminate the cycle in cases where your application starts and exits normally.