Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specifying default arguments for main

Tags:

kotlin

What am I doing wrong here?

fun main(args: Array<String> = arrayOf("abc")) {
    val a = args[0]
}

compiles fine but:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0

I want to make it optional to have an argument and supply a default value if none was specified

like image 254
ycomp Avatar asked Feb 20 '19 14:02

ycomp


2 Answers

This probably does not work because of how the underlying Java platform works and how Kotlin translates default arguments to something the JVM can understand. You could say it's a bug in Kotlin...

The Java virtual machine looks for a method with the following signature to run your program (this is Java):

public static void main(String[] args)

Note that default argument values do not exist in Java, so if you declare a method with default values in Kotlin, the Kotlin compiler generates multiple methods in the Java byte code that will look like this when converted to Java:

public static void main(String[] args) {
    // the normal main method
}

// generated because you have a method with default values
public static void main() {
    main(new String[]{ "abc" });
}

When you run the program, the JVM will still look for the method with the String[] args argument. It will ignore the method with no arguments, that was generated for the Kotlin main method with default arguments.

So it's always going to call the String[] args version, even if there are no arguments on the command line - leading to the error that you get.

Workaround: Don't use default values for the main method; check if arguments were given inside the method:

fun main(args: Array<String>) {
    val realArgs = if (args.size > 0) args else arrayOf("abc")

    // work with realArgs
}
like image 166
Jesper Avatar answered Sep 26 '22 03:09

Jesper


I think it's a question of signature the JVM's search for main methods: a main method should have one parameter of String[] type, and this parameter receives value(s) from CLI; if the CLI does not provide any parameter, the main method receives a new String[0], which causes the error you're experiencing.

I think you can solve the problem slightly changing the approach:

fun main(args: Array<String>) {
    println(args)
    val a = args.getOrElse(0) {"abc"}
    println(a)
}

should work for your scenario: if there is no parameter with index 0 a gets the default value you passed (as a lambda) to getOrElse.

like image 23
Pietro Martinelli Avatar answered Sep 27 '22 03:09

Pietro Martinelli