Fenix 3 HR 4.30: UnexpectedTypeException: Expected Method, given Class definition

Former Member
Former Member
I made a program for the Fenix 5x series. Everything works fine on that watch. Tested it very very well. Now someone is running into problems starting the app. He uses a Fenix 3 HR 4.30. He immediatly gets an IQ screen. I debugged the program and the problem is occuring by getting a setting in the following statement:

var turns = App.getProperty("turns");

It's the first statement getting the settings. The var turns is stored as string in the object store. It's a very common statement. Has someone any idea how to fix this? I'm lost, I tried every workaround.
  • Former Member
    Former Member over 7 years ago
    using Toybox.Application as App;

    ---------------------------------------------------------

    class GameApp extends App.AppBase {
    -------------------------------------------------------

    var turns = GameApp.getProperty("turns");

    In simulator (5x and 3hr) and on watch 5x it works perfect, I don't understand why it isn't working on a 3 HR watch.

    I tried all: App, GameApp, Application etc....I changed the name of the var. I changed the statement in: var turns = ""; turns = GameApp.getProperty("turns");

    None of them is working on 3HR.
  • Try

    var turns = App.getApp().getProperty("turns");

  • Former Member
    Former Member over 7 years ago
    Solved!!!!!

    I used the statement: appName = Application.getApp();

    and then

    var turns = appName.getProperty("turns");

    I thought Monkey C was designed to be OO. It is, but not on all devices
  • This isn't really a question of the language being object oriented or not. Toybox.Application (or the alias App that you created with the using clause) is a class/module. Calling a method on a class/module only works if that method is a class/module method (i.e., it is static). You are trying to call an instance method, so you need an instance of a class to call it on.

    You'd get very similar errors if you tried the following code in C++..

    namespace Toybox
    {
    namespace Application {
    class AppBase {
    void getProperty(const char* name);
    };

    static AppBase& getApp();
    }
    }

    int main() {
    Toybox::Application::getProperty("test");
    }


    C:\Users\vitek\Desktop>cl /c t.cpp
    Microsoft (R) C/C++ Optimizing Compiler Version 18.00.40629 for x86
    Copyright (C) Microsoft Corporation. All rights reserved.

    t.cpp
    t.cpp(20) : error C2039: 'getProperty' : is not a member of 'Toybox::Application'
    t.cpp(20) : error C3861: 'getProperty': identifier not found

  • Former Member
    Former Member over 7 years ago
    Clear, but can you explain to me why the runtime engine on a Fenix 5x works in another way than the engine on a Fenix 3 HR? Why does the first statement work perfectly on a 5x and not on a 3HR? I think it's a bug in the environment. Normally wrong==wrong!
  • I've been unable to create a test case that works in the simulator and fails anywhere else when I'd expect it to fail. Here is the test case that I wrote. It shows white text for the things that are expected to work. If you press enter/select, it will try, and change the text to green on success. Things that are expected to fail (because of symbol not found errors) are colored in red. If you try them and they work, the text would switch from red to green.

    using Toybox.Application as App;
    using Toybox.Graphics as Gfx;
    using Toybox.WatchUi as Ui;
    using Toybox.System as Sys;


    enum {
    EXPECTED_FAIL = -1,
    EXPECTED_SUCCESS = 0,
    VERIFIED_SUCCESS = 1
    }

    class GameBehaviorDelegate extends Ui.BehaviorDelegate {

    hidden var mModel;

    function initialize(model) {
    BehaviorDelegate.initialize();
    mModel = model;
    }

    function onNextPage() {
    mModel.updateMode(+1);
    Ui.requestUpdate();

    return true;
    }

    function onPreviousPage() {
    mModel.updateMode(-1);
    Ui.requestUpdate();

    return true;
    }

    function onSelect() {
    mModel.testMode();
    Ui.requestUpdate();

    return true;
    }

    }

    class GameView extends Ui.View {

    hidden var mModel;

    function initialize(model) {
    View.initialize();
    mModel = model;
    }

    function onUpdate(dc) {
    dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
    dc.clear();

    var cx = dc.getWidth() / 2;
    var cy = dc.getHeight() / 2;

    var value = mModel.getModeValue();
    if (EXPECTED_FAIL == value) {
    dc.setColor(Gfx.COLOR_RED, Gfx.COLOR_BLACK);
    }
    else if (VERIFIED_SUCCESS == value) {
    dc.setColor(Gfx.COLOR_GREEN, Gfx.COLOR_BLACK);
    }
    else {
    dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_BLACK);
    }

    var name = mModel.getModeName();
    dc.drawText(cx, cy, Gfx.FONT_TINY,
    name,
    Gfx.TEXT_JUSTIFY_CENTER | Gfx.TEXT_JUSTIFY_VCENTER);
    }

    }

    class GameApp extends App.AppBase {

    function initialize() {
    AppBase.initialize();
    }

    function getInitialView() {
    return [ new GameView(self), new GameBehaviorDelegate(self) ];
    }

    hidden var mMode = 0;


    const mModes = {
    "GameApp.getProperty(0)" => [ :test_call_mode_properly_qualified , EXPECTED_SUCCESS ],
    "AppBase.getProperty(0)" => [ :test_call_mode_properly_qualified_base , EXPECTED_SUCCESS ],
    "self.getProperty(0)" => [ :test_call_mode_properly_qualified_self , EXPECTED_SUCCESS ],
    "getProperty(0)" => [ :test_call_mode_unqualified , EXPECTED_SUCCESS ],
    "App.getProperty(0)" => [ :test_call_mode_improperly_qualified_app , EXPECTED_FAIL ],
    "Application.getProperty(0)" => [ :test_call_mode_improperly_qualified_application, EXPECTED_FAIL ]
    };

    function updateMode(direction) {

    if (direction < 0) {

    if (0 == mMode) {
    mMode = mModes.size();
    }

    mMode -= 1;
    }
    else {

    mMode += 1;

    if (mModes.size() == mMode) {
    mMode = 0;
    }
    }

    }

    function testMode() {

    // given the selected mode, get the symbol and used flag array
    var mode = mModes[ mModes.keys()[mMode] ];

    // given the symbol, get the a function wrapper
    var callable = self.method(mode[0]);

    // invoke the function wrapper
    callable.invoke();

    // set flag indicating mode has been used successfully
    mode[1] = VERIFIED_SUCCESS;
    }


    function getModeName() {
    return mModes.keys()[mMode];
    }

    function getModeValue() {
    return mModes [ mModes.keys()[mMode] ][1];
    }

    function test_call_mode_properly_qualified() {
    GameApp.getProperty(0);
    }

    function test_call_mode_properly_qualified_base() {
    AppBase.getProperty(0);
    }

    function test_call_mode_properly_qualified_self() {
    self.getProperty(0);
    }

    function test_call_mode_unqualified() {
    getProperty(0);
    }

    function test_call_mode_improperly_qualified_app() {
    App.getProperty(0);
    }

    function test_call_mode_improperly_qualified_application() {
    Application.getProperty(0);
    }

    }


    If you are still able to demonstrate the problem, could you supply a test case?

    Travis
  • Former Member
    Former Member over 7 years ago
    The error occurs when you put the functions in a separate mc file or perhaps outside the last curly bracket and you refer to GameApp.
  • Outside of GameApp none of the calls listed in my test code above should work. I'm away from my development environment at the moment, but I struggle to imagine a scenario where one of them would.

    Travis
  • I hate to jump in here, but this bug report sorta intrigued me. Wish I had a 235 (or other CIQ1 device) to test on, but how about the following code snippet?

    Both of the getProperty() calls are resolved in the sim, but maybe the 2nd one fails on CIQ1....

    using Toybox.Application as App;
    using Toybox.WatchUi as Ui;
    using Toybox.System;

    class test2App extends App.AppBase {
    function initialize() {
    AppBase.initialize();

    var turns = test2App.getProperty("turns"); // I bet this works
    System.println("turns = " + turns); // does not need "using"
    testCase();
    }
    }

    function testCase() {
    var turns = test2App.getProperty("turns"); // I bet this fails on CIQ1 (works in the sim)
    System.println("turns (2) = " + turns); // needs "using"
    }


    Also, I think this has been reported already, but the 2nd usage of System (in testCase()) requires the "using Toybox.System" statement, but the first usage (in test2App.initialize()) does not.