ConnectIQ 2.3.1: method(:myMethod).invoke()= could not find symbol method (sometimes)

A Descriptive Title
method(:testMethod) gives an error in certain contexts. Used to work fine on ConnectIQ 2.2.6

The Environment:
- OS X and Windows
- Eclipse Neon.2 (4.6.2) and Mars (4.5.2)
- ConnectIQ 2.3.1

A detailed description of the issue
- A function testMethod() is created out of a class and without explicitly defining a module.
- It can be called from inside a class and from other functions at the same level
- It can also be called from inside a class using method(:testMethod).invoke()
- It can also be called from other functions at the same level if method(:testMethod) is passed as a parameter and then .invoke() is called on this parameter.
- But if you use method(:testMethod) in a function on that same level, you get a runtime error: "Could not find symbol method"

It worked fine on ConnectIQ 2.2.6, both on simulator and real devices. Is it a bug or not allowed anymore?


Steps to reproduce the issue

using Toybox.WatchUi as Ui;
using Toybox.System as Sys;

class TestFooView extends Ui.View {

function onUpdate(dc) {
// Call the parent onUpdate function to redraw the layout
View.onUpdate(dc);

Sys.println("Calling testMethod() from TestFooView class.");
testMethod();

Sys.println("Calling method(:testMethod).invoke() from TestFooView class.");
method(:testMethod).invoke();

Sys.println("Calling callTestMethodFromTheSameLevel() from TestFooView class.");
callTestMethodFromTheSameLevel();

Sys.println("Calling receiveMethodObjAndInvoke(method(:testMethod)) from TestFooView class.");
receiveMethodObjAndInvoke(method(:testMethod));

Sys.println("Calling createMethodObjAndInvoke() from TestFooView class.");
createMethodObjAndInvoke();
}

function onHide() {}
function initialize() {View.initialize();}
function onLayout(dc) {setLayout(Rez.Layouts.MainLayout(dc));}
function onShow() {}
}

function callTestMethodFromTheSameLevel(){
Sys.println(" callTestMethodFromTheSameLevel() calls testMethod()");
testMethod();
}

function receiveMethodObjAndInvoke(aMethod){
Sys.println(" receiveMethodObjAndInvoke(aMethod) calls aMethod.invoke()");
aMethod.invoke();
}

function createMethodObjAndInvoke(){
Sys.println(" createMethodObjAndInvoke() calls method(:testMethod).invoke()");
method(:testMethod).invoke(); // <------------------------------------------ HERE IS THE PROBLEM!
}

function testMethod(){
Sys.println("-> OK! testMethod() responded.");
}


Output CIQ 2.3.1:
Calling testMethod() from TestFooView class.
-> OK! testMethod() responded.
Calling method(:testMethod).invoke() from TestFooView class.
-> OK! testMethod() responded.
Calling callTestMethodFromTheSameLevel() from TestFooView class.
callTestMethodFromTheSameLevel() calls testMethod()
-> OK! testMethod() responded.
Calling receiveMethodObjAndInvoke(method(:testMethod)) from TestFooView class.
receiveMethodObjAndInvoke(aMethod) calls aMethod.invoke()
-> OK! testMethod() responded.
Calling createMethodObjAndInvoke() from TestFooView class.
createMethodObjAndInvoke() calls method(:testMethod).invoke()
Could not find symbol method.Failed invoking <symbol>Symbol Not Found Error
in createMethodObjAndInvoke (C:\Users\rrezende\workspace\TestFoo\source\TestFooView.mc:44)
in onUpdate (C:\Users\rrezende\workspace\TestFoo\source\TestFooView.mc:23)


Output CIQ 2.2.6:
Calling testMethod() from TestFooView class.
-> OK! testMethod() responded.
Calling method(:testMethod).invoke() from TestFooView class.
-> OK! testMethod() responded.
Calling callTestMethodFromTheSameLevel() from TestFooView class.
callTestMethodFromTheSameLevel() calls testMethod()
-> OK! testMethod() responded.
Calling receiveMethodObjAndInvoke(method(:testMethod)) from TestFooView class.
receiveMethodObjAndInvoke(aMethod) calls aMethod.invoke()
-> OK! testMethod() responded.
Calling createMethodObjAndInvoke() from TestFooView class.
createMethodObjAndInvoke() calls method(:testMethod).invoke()
-> OK! testMethod() responded.
  • The call stack indicates you didn't remove the onPhone() stuff from your view class.

    Ok, changed that but now the error is on calling enableHRSensor();, that was before global:

    ERROR: Symbol Not Found Error
    DETAILS: Could not find symbol enableHRSensor.
    STORE_ID: 00000000000000000000000000000000
    CALLSTACK:
    /home/cas/BodyFatControl/garmin_watchface/source/BodyFatControl_garmin_watchappView.mc (startSportMode:90)
    /home/cas/BodyFatControl/garmin_watchface/source/BodyFatControl_garmin_watchappView.mc (onKey:471)
    @PC = 0x30001c0d
    @PC = 0x30001e38

    I don't know if is possible to make the code without using globals :-(

    Code here: https://github.com/BodyFatControl/garmin_watchface/tree/testing/source
  • I don't know if is possible to make the code without using globals :-(

    Of course it is possible. That function is a member of the app object, so you've got to call that function on the app object.

    Travis

  • Of course it is possible. That function is a member of the app object, so you've got to call that function on the app object.

    Travis



    Thanks!! Got the app fully working again however I call Ui.requestUpdate(); from a method inside class BodyFatControl extends App.AppBase { and it works... I was not expect that. Anyway, it is fully working now :-)
  • It is unlikely that we'll be part of the discussion on the fix.

    Well, I was wrong about this part. ;D

    It only requires refactoring if you want to make your code 'more correct'. If you just want to work around the problem...

    But I'm right about this part.

    The new behavior is as intended. This was codified in the programmer's guide here. I didn't look to see when the documentation was updated, but the fact that it was is a pretty good indicator this decision was by design.

    Travis