Search code examples
kotlinjvmcompiler-construction

Why is @JVMStatic annotation necessary for Kotlin main function?


Recently started learning Kotlin. I noticed an interesting behaviour when declaring the main function in Kotlin. It uses a @JvmStatic annotation even when in an object class. I looked around and did not find a relevant post.

object Main {
    @JvmStatic
    fun main(args: Array<String>) {
        println("Hello World")
    }
}

Why does the main function in Kotlin require a @JvmStatic annotation?

Coming from a Java and Scala background, it seems redundant and unnecessary, so I am curious what the background context and decision making was that made Kotlin adopt this convention.


Solution

  • @JvmStatic is not required if you declare main as a top-level function. That is, if the entirety of your Kotlin source file is:

    fun main(args: Array<String>) {
        println("Hello World")
    }
    

    You do not need @JvmStatic in this case - all top-level functions are translated to a static method in Java, in a class called XXXKt by default, where XXX is your Kotlin file name.

    Note that for parameterless top-level mains in Kotlin, the compiler actually generates a proper Java main that takes String[] args, and delegate to your Kotlin function.

    // the Kotlin main gets converted to something like this...
    public static void main$1() {
        // your kotlin code here...
    }
    
    // A proper Java main generated by Kotlin
    public static void main(String[] args) {
        main$1();
    }
    

    You do need @JvmStatic when you put the main method inside an object, because objects are translated to a singleton class in Java. All the members in the object are non-static by default.

    object MyObject {
        fun main(args: Array<String>) {
    
        }
    }
    

    is translated to something like this:

    public final class MyObject {
        private MyObject() {}
    
        public static final MyObject INSTANCE = new MyObject();
    
        public void main(String[] args) { }
    }
    

    When you do MyObject.main(...) in Kotlin, it is actually MyObject.INSTANCE.main(...) in Java. Obviously, such a main method cannot be used as the entry point of a Java program, because it is not static.