Can I pass a lambda as function parameter?

Can I somehow avoid the need to define a local function for each function that I need to pass into a class?

E.g. check out following:

function createDataProviderNone() as IDataProvider { return new DataNone(); }
function createDataProviderBattery() as IDataProvider { return new DataBattery(false); }
function createDataProviderBatteryInDays() as IDataProvider { return new DataBattery(true); }

static const NONE =                     new DataType(0, "--", new Lang.Method(:createDataProviderNone));
static const BATTERY =                  new DataType(1, "Battery (%)", new Lang.Method(:createDataProviderBattery));
static const BATTERY_IN_DAYS =          new DataType(2, "Battery (Days)", new Lang.Method(:createDataProviderBatteryInDays));

I want to define my data type instances once and I want them to have a function that will return the underlying data provider instance - I can do this like I do it above, but I would prefer some inlined style like following:

static const NONE =                     new DataType(0, "--", new Lang.Method({ return new DataNone(); }));
static const BATTERY =                  new DataType(1, "Battery (%)", new Lang.Method({ return new DataBattery(false); });
static const BATTERY_IN_DAYS =          new DataType(2, "Battery (Days)", new Lang.Method({ return new DataBattery(true); });

But that is not working. Is there a syntax to achieve what I want? I want the equivalent to following in C++:

 static const NONE = new DataType(0, "--", new std::function([](){ return new DataNone(); });

  • I don't think it's possible with the current compiler, but it sounds like a reasonable feature request (and maybe even not too hard to implement, probably just syntactic sugar). You can open a feature-request here:  forums.garmin.com/.../bug-reports

  • More annoying is that I need to cast everything like following and to move the functions inside a module as I could not get it working with static functions in the class itself nor without casting:

    module DataTypeCreators
    {
        function createNone(type as DataType) as IDataProvider { return new DataNone(); }
    }
    
    class DataType
    {
        private var create as Method(type as DataType) as IDataProvider;
    
        static const NONE = new DataType(0, "--", new Method(DataTypeCreators, :createNone) as Method(type as DataType) as IDataProvider);
    }

    As far as I can see feature requests never get implemented so I just use what I can use so far...

  • if you move createNone into DataType then you can use this from within DataType:

    method(:createNone)

  • Not if I define the instances as static... I can define them inside DataType as well of course, but even then I need to cast each method... Otherwise I always get an exception like following:

     Passing '$.Toybox.Lang.Method' as parameter 3 of type '$.Toybox.Lang.Method(type as $.DataType) as interface { var data as $.Data; function load(dataManager as $.DataManager) as Void; var type as $.DataType; }'

    This error seems to be a compiler bug I think, as it simply is not true and after casting everything is fine and works as expected...

  • I agree, and I think it's worth to file a bug report about it. These get fixed usually in the next SDK version.

  • but even then I need to cast each method...

    Could you include a working skeleton example, so we can reproduce the problem you are having? The code you posted is missing things like:

    - the definition of DataType.initialize()

    - the definition of IDataProvider

    - an example implementation of IDataProvider (such as DataNone())

  • Here it is, a minimal example:

    IMPL2 gives following error:

    ERROR: fenix847mm: M:\dev\02 - apps - garmin\shared2\src\data\classes\Test.mc:32,17: Passing '$.Toybox.Lang.Method' as parameter 1 of type '$.Toybox.Lang.Method(test as $.Test) as interface { var test as $.Test; }'.

    Whereas IMPL1 with the cast does not give any error..

    Code:

    import Toybox.Lang;
    import Toybox.System;
    
    typedef ITestInterface as interface {
        var test as Test;
    };
    
    module TestCreators
    {
        function createIMPL1(test as Test) as ITestInterface { return new TestInterfaceImpl(test); }
        function createIMPL2(test as Test) as ITestInterface { return new TestInterfaceImpl(test); }
    }
    
    class TestInterfaceImpl
    {
        var test as Test;
    
        function initialize(test as Test) {
            self.test = test;
        }
    }
    
    class Test
    {
        private var create as Method(test as Test) as ITestInterface;
    
        function initialize(create as Method(test as Test) as ITestInterface) {
            self.create = create;
        }
    
        static const IMPL1 = new Test(new Method(TestCreators, :createIMPL1) as Method(test as Test) as ITestInterface);
        static const IMPL2 = new Test(new Method(TestCreators, :createIMPL1));
    }

  • Yeah the casting requirement here seems pretty annoying. It seems that Lang.Method.initialize() isn't able to infer the method type in the same way as Lang.Object.method().

    Is it absolutely necessary to move your static functions into a separate module? Does the following mod work:

    class Test extends Lang.Object
    {
        private var create as Method(test as Test) as ITestInterface;
    
        function initialize(create as Method(test as Test) as ITestInterface) {
            self.create = create;
        }
    
        // new code
        static function createIMPL3(test as Test) as ITestInterface {
            return new TestInterfaceImpl(test);
        }
    
        static const IMPL1 = new Test(new Method(TestCreators, :createIMPL1) as Method(test as Test) as ITestInterface);
        static const IMPL2 = new Test(new Method(TestCreators, :createIMPL1));
        // new code
        static const IMPL3 = new Test(new Method(Test, :createIMPL3) as Method(test as Test) as ITestInterface);
    }
    
    

    For me, the line with IMPL3 at least compiles without warnings or errors.

    EDIT: nvm when I actually run the code, I get a circular dependency error at line 11 of my snippet above: return new TestInterfaceImpl(test)

  • Is it absolutely necessary to move your static functions into a separate module?

    No it isn't... Just made it like that to separate the implementations from the class definition...

    For me, the line with IMPL3 at least compiles without warnings or errors.

    Sure, that works as well for me.

    The issue is just the need for the manual cast... (and that I can't define the methods in an inline way)