Static access to inherited constants behaves differently than instance access

I recently noticed some unexpected behavior and would appreciate your thoughts on whether this is intended or a bug.

In my app, I use classes that define constants to control various device-specific aspects. There is a base class that provides default values, and derived classes can override selected constants as needed.

This works fine when accessing the constants from instance methods. However, when I try to access them from a static method, I can only access constants that are explicitly defined in the concrete class. Inherited constants are not accessible.

Here is a simplified example:

import Toybox.Lang;

class ConstantsA {
    public static const X as Number = 1;
    public static const Y as Number = 2;
    public static const Z as Number = 3;
}

class ConstantsB extends ConstantsA {
    public static const Y as Number = 2;
    public static const Z as Number = ConstantsA.Z;
}

class ConstantsC extends ConstantsA {
    public static const Y as Number = 2;
    public static const Z as Number = ConstantsB.Z;
}

class ConstantsTest {
    public function test() as Void {
        Toybox.System.println( ConstantsC.X ); // Works
        Toybox.System.println( ConstantsC.Y ); // Works
        Toybox.System.println( ConstantsC.Z ); // Works
    }
    public static function testStatic() as Void {
        Toybox.System.println( ConstantsC.X ); // Does not work
        Toybox.System.println( ConstantsC.Y ); // Works
        Toybox.System.println( ConstantsC.Z ); // Works
    }
}

In this example, ConstantsC.X is accessible from the instance method but not from the static method, even though it is defined in the base class.

In the static method, I receive the following error:

ERROR: edge840: D:\GitHub\ohg\source\test.mc:26,8: Cannot find symbol ':X' on class definition '$.ConstantsC'.

Is there a logical explanation for this behavior? Or does this appear to be a bug in the language or compiler?

Any insight would be greatly appreciated.

  • Your test is wrong. You should set different values to Y, you might discover funny things (in theory, I'm not saying it happens)

  • Have you tried if it works on older SDK-s?

  • Your test is wrong. You should set different values to Y, you might discover funny things (in theory, I'm not saying it happens)

    I am using this model extensively throughout my app, assigning different values in the subclasses. In general, everything works as expected. The only issue I am unsure about is this specific compiler error that occurs when I try to use it within a static function.

    At the moment, I am handling those constants needed in static functions the same way I handled “Z” in the example. It requires a bit of additional effort, but it works reliably.

    Have you tried if it works on older SDK-s?

    I went back to 7.4.3, but the code still fails with the same error.

  • Y = 2 everywhere. So if you see it prints that Y is 2 you can't be sure it's coming from what you expect or from another class. Use 5 different numbers !

  • This example is only intended to reproduce the compiler error. The specific values assigned are irrelevant for this.

  • I guess the inherited constants are non static and can't be accessed by a static function. My brain hurts when I try to think this far back in programming. I guess it might have something to do with parsing pointers or values.

  • The fact that the non-static funtion can access X seems logical, because the non static funtion is an instance method (it requires an instance of ConstantsC) to call it, and static constants are shared by all instances of a class. The static function is not an instamce method, and by calling it you do not access an instance. You do not even access a class, the symbol ConstantC is treated as a Module, so purely a name space. And in Modules there is no inheritance. So calling static ConstantsC.X, you will get a 'symbol not found on ConstantsC' and that is correct because module ConstantsC has no member X, end modules do not inherit. Just my interpretation.

  • sorry for the type-o's, my keyboard is too small for my hands I guess ;)

  • You do not even access a class, the symbol ConstantC is treated as a Module, so purely a name space. And in Modules there is no inheritance.

    Yes, that could explain it. If the compiler resolves ConstantsC as a class type when accessed from an instance method, but treats it as a module or namespace when accessed from a static method, then inheritance would not apply in the latter context.

  • BTW I think that you can add static before the const. I don't have the computer here, but you could try if that changes anything