Search code examples
kotlinscoping

kotlin ...ArrayOf scoping issues


Why does the first sample of code below compile but the second fails. The only change is that I've moved the val involved from file scope to class scope.

longArrayOf(...) creates a LongArray, right?

Compiles with no problem:

val CORRECT_BUZZ_PATTERN = longArrayOf(100, 100, 100, 100, 100, 100)
class TestLongArrayOf {
    enum class BuzzType(val pattern: LongArray) {
        CORRECT(CORRECT_BUZZ_PATTERN)
    }
}


Fails with message "unresolved reference CORRECT_BUZZ_PATTERN"

class TestLongArrayOf {
    val CORRECT_BUZZ_PATTERN = longArrayOf(100, 100, 100, 100, 100, 100)
    enum class BuzzType(val pattern: LongArray) {
        CORRECT(CORRECT_BUZZ_PATTERN)
    }
}

Solution

  • The main difference is that in the first case CORRECT_BUZZ_PATTERN is defined outside of the class and is treated as read-only variable (accessible through its getter), while in the second snippet it's a read-only instance variable, so it cannot be used as a constant. However, this code would work:

    class TestLongArrayOf {
        val CORRECT_BUZZ_PATTERN = longArrayOf(100, 100, 100, 100, 100, 100)
        enum class BuzzType(val pattern: LongArray) {
            CORRECT(TestLongArrayOf().CORRECT_BUZZ_PATTERN)
        }
    }
    

    Let's look at the generated bytecode. In the first case you have:

    public final class MainKt {
        private final static long[] CORRECT_BUZZ_PATTERN
        public final static long[] getCORRECT_BUZZ_PATTERN() {
            ...
        }
        static {
            // initialize CORRECT_BUZZ_PATTERN here
            ...
        }
    }
    
    public final enum TestLongArrayOf$BuzzType {
        ...
    }
    

    So CORRECT_BUZZ_PATTERN is a static final array belonging to class MainKt that can be accessed through its getter.

    In the second case what you get is:

    public final class TestLongArrayOf {
        private final long[] CORRECT_BUZZ_PATTERN
    
        public final long[] getCORRECT_BUZZ_PATTERN() {
            ...
        }
    }
    
    public final enum TestLongArrayOf$BuzzType { 
        ...
    }
    

    Note that in this case CORRECT_BUZZ_PATTERN is an instance variable that can be retrieved via its getter. However, since it's an instance variable you must call the getter on an instance of TestLongArrayOf, that's why the snippet at the top of my answer is working.