Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

kotlin function default arguments from java

Tags:

kotlin

given following Kotlin class:

class Foo {    public fun bar(i: Int = 0): Int = 2 * i } 

How should I call 'bar' function without any parameter from a java/groovy code?

def f = new Foo() f.bar() //throws:  java.lang.IllegalArgumentException: Parameter specified as non-null contains null 
like image 351
mhshams Avatar asked Jun 27 '13 16:06

mhshams


People also ask

How do you pass a default parameter in Kotlin?

Kotlin Default Argument In Kotlin, you can provide default values to parameters in function definition. If the function is called with arguments passed, those arguments are used as parameters. However, if the function is called without passing argument(s), default arguments are used.

Can you pass functions as parameters in Kotlin?

Kotlin functions are first-class, which means they can be stored in variables and data structures, and can be passed as arguments to and returned from other higher-order functions. You can perform any operations on functions that are possible for other non-function values.

What is the default return type of a function in Kotlin?

I know unit is the default return type in kotlin.


2 Answers

You can do this now in Kotlin. For your class method, use the @JvmOverloads annotation.

class Foo {     @JvmOverloads public fun bar(name: String = "World"): String = "Hello $name!" } 

Now simply call it from Java:

Foo foo = new Foo(); System.out.println(foo.bar()); System.out.println(foo.bar("Frank")); 

Outputs the following:

Hello World!

Hello Frank!

like image 129
2 revs Avatar answered Sep 19 '22 17:09

2 revs


I'll post the real answer shortly, but if anyone is wanting to do this from reflection, here is how the code would look. Much more complicated, but educational about how to use Kotlin reflection for KCallable.

Here is the class to call:

 class Foo {     public fun bar(name: String = "World"): String = "Hello $name!" } 

Then we need a utility class in Kotin that can receive an instance of a class, a method from java reflection, and the parameters by name. This only works with non-primitives:

class KReflectHelper {     companion object {         @Suppress("UNCHECKED_CAST")         @JvmStatic fun <T> callKotlinMethodWithNamedParms(instance: Any, method: Method, parmMap: Map<String, Any>): T {             val callable: KFunction<T> = method.kotlinFunction as? KFunction<T> ?: throw IllegalStateException("Method is not a Kotlin method")             val unusedParms = HashSet(parmMap.keys)             val callableParms = hashMapOf<KParameter, Any?>()             callable.parameters.map { parm ->                 if (parm.kind == KParameter.Kind.INSTANCE) {                     callableParms.put(parm, instance)                 } else if (parm.kind == KParameter.Kind.VALUE && parmMap.contains(parm.name)) {                     unusedParms.remove(parm.name)                     callableParms.put(parm, parmMap.get(parm.name))                 } else if (parm.kind == KParameter.Kind.VALUE) {                     if (parm.isOptional) {                         // default value will be used!                     } else {                        throw IllegalStateException("Missing required parameter ${parm.name}")                     }                 } else {                     throw IllegalStateException("Cannot call methods that are not direct instance methods")                 }             }             if (unusedParms.isNotEmpty()) {                 throw IllegalStateException("Unrecognized parameters passed to function: $unusedParms")             }             return method.kotlinFunction?.callBy(callableParms) as T         }     } } 

Now that static method can be called from Java, but it isn't so much fun. A code generator would really be required. Calling it from Kotlin is much easier and some frameworks (such as Klutter and Kovert) already use something along these lines.

    Foo foo = new Foo();     System.out.println(foo.bar("Frank"));      Method barMethod = Foo.class.getMethod("bar", String.class);      Map<String, Object> parms = new HashMap<String, Object>();      parms.put("name", "David");     System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms));      // now call using the default     parms.clear();     System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms)); 

Ouput:

Hello Frank!

Hello David!

Hello World!

like image 23
2 revs Avatar answered Sep 16 '22 17:09

2 revs