Search code examples
kotlincompanion-objectkotlin-companion

object instances in companion objects


This is a question about language design rather than trying to solve a specific problem.

I noted two oddities about object instances inside companion objects:

  • object instances can't be referenced without the .Companion
  • object instances cannot be annotated @JvmStatic

As shown below, neither constraint applies to functions defined within companion objects. The distinction for apparently for what appear to be sibling declarations is a bit of mental overhead I'd rather not have to deal with.

Is there an example that demonstrates why these constraints were necessary? Presumably for Java interop, but I have yet to think of the case.

class MyClass {
    companion object {
        @JvmStatic
        fun myFunc() {}
       
        //@JvmStatic // Error: This annotation is not applicable to target 'standalone object'
        object MyObject {}
    }
}

fun testingReferencing() {
    MyClass.myFunc()
    MyClass.Companion.myFunc()  // Awkward and redundant, but works.
    
    //val obj1 = MyClass.MyObject  // Error: Unresolved reference: MyObject
    val obj2 = MyClass.Companion.MyObject
}

https://pl.kotl.in/LJQLiBe6m


Solution

  • object instances can't be referenced without the .Companion

    This "restriction" is certainly not "necessary", but enabling you to access object declarations this way would probably lead to more complexity in the compiler, to not only implement this, but also handle the edge cases, and various other features that might interact with the change.

    And anyway, this is how type names work all along. The fact that you can access properties and methods without Companion is the exception.

    MyClass.MyObject refers to an object/type called MyObject, nested in MyClass. And MyClass.Companion.MyObject refers to an object/type called MyObject nested in a type called Companion, which is itself nested in a type called MyClass.

    This is just the way nested type names (whether they are objects, classes, or interfaces) are qualified.

    object instances cannot be annotated @JvmStatic

    JvmStatic is just unnecessary on type declarations. If you look at the annotation's declaration, it is only available on functions and properties.

    An object (or class, or enum class) declaration nested in another type already translates to a static nested class in Java. e.g.

    class Foo {
        object Bar
    }
    

    translates to something like

    public class Foo {
        public static class Bar {
            public static final INSTANCE = new Bar();
            private Bar() {}
        }
    }
    

    Whether or not it is in a companion object doesn't matter. companion object, just like class, translates to a Java class, where the class for the object is nested.

    If you want a non-static JVM class, that is an inner class in Kotlin.