Accessing a function's default parameter value in Kotlin
Asked Answered
C

1

6

Can a function's default parameter value be accessed from a function extension, or anywhere else?

fun DieRoll.cheatRoll():Int = roll(min = max -1)

fun roll(min: Int = 1, max: Int = 6): Int = (min..max).rand()
Colter answered 20/8, 2017 at 20:16 Comment(2)
No, it cannot. Since a default value of a parameter can be aribtrary expression with possible side effects, it would not be quite clear and intuitive to use it anywhere explicitly: what should be the semantics, should it be evaluated on each use or not?Selfsown
What about just storing the min and max values as constants? That would make access visibility better too.Foreconscious
T
5

No, this is not possible. The default values are not accessible. They are just contained in a bridge-method in the bytecode:

fun test(a: Int = 123) {
}

fun test2() {
    test()
    test(100)
}

Results in the bytecode:

public final test(int arg0) { //(I)V
     <localVar:index=0 , name=this , desc=Lorg/guenhter/springboot/kt/Fun;, sig=null, start=L1, end=L2>
     <localVar:index=1 , name=a , desc=I, sig=null, start=L1, end=L2>

     L1 {
         return
     }
     L2 {
     }
 }

 public static bridge test$default(org.guenhter.springboot.kt.Fun arg0, int arg1, int arg2, java.lang.Object arg3) { //(Lorg/guenhter/springboot/kt/Fun;IILjava/lang/Object;)V
         iload2 // reference to arg2
         iconst_1
         iand
         ifeq L1
     L2 {
         bipush 123  // <-- THIS IS YOUR DEFAULT VALUE
         istore1 // reference to arg1
     }
     L1 {
         aload0 // reference to arg0
         iload1 // reference to arg1
         invokevirtual org/guenhter/springboot/kt/Fun test((I)V);
         return
     }
 }

 public final test2() { //()V
     <localVar:index=0 , name=this , desc=Lorg/guenhter/springboot/kt/Fun;, sig=null, start=L1, end=L2>

     L1 {
         aload0 // reference to self
         iconst_0
         iconst_1
         aconst_null
         invokestatic org/guenhter/springboot/kt/Fun test$default((Lorg/guenhter/springboot/kt/Fun;IILjava/lang/Object;)V);
     }
     L3 {
         aload0 // reference to self
         bipush 100
         invokevirtual org/guenhter/springboot/kt/Fun test((I)V);
     }
     L4 {
         return
     }
     L2 {
     }
 }

which in Java syntax would look like

final public class AKt {
    final public static void test(int i) {
    }

    public static void test$default(int i, int i0, Object a) {
        if ((i0 & 1) != 0) {
            i = 123;
        }
        AKt.test(i);
    }

    final public static void test2() {
        AKt.test$default(0, 1, (Object)null);
        AKt.test(100);
    }
}

So the best alternative for you would be to extract the default value into a constant:

private val DEFAULT_MIN = 1
private val DEFAULT_MAX = 1

fun DieRoll.cheatRoll():Int = roll(min = DEFAULT_MAX-1)

fun roll(min: Int = DEFAULT_MIN, max: Int = DEFAULT_MAX): Int = (min..max).rand()
Turkestan answered 21/8, 2017 at 13:8 Comment(1)
To understand in detail: medium.com/@khadijahameed415/…Vicereine

© 2022 - 2024 — McMap. All rights reserved.