Assuming a kotlin function like this:
fun f(p1: T1? = null, p2: T2? = null, ..., pN: TN? = null) {
// ...
}
Can the above function's implementation distinguish between the following two calls, where the first one passed p1 = null
implicitly, and the second one passed it explicitly?
f() // Implicit
f(null) // Explicit
f(p1 = null) // Explicit
Note: There could be arbitrary numbers of parameters
A default value is defined using = after the type. Overriding methods always use the same default parameter values as the base method. When overriding a method that has default parameter values, the default parameter values must be omitted from the signature: open class A { open fun foo(i: Int = 10) { /*...
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.
Since Kotlin is a new language for JVM, like Java it is pass-by-value.
In Kotlin, You can pass a variable number of arguments to a function by declaring the function with a vararg parameter. a vararg parameter of type T is internally represented as an array of type T ( Array<T> ) inside the function body.
No, it cannot distinguish between those cases.
You could distinguish between them if you added a distinct overload, however.
Although I'd rather not use that approach in production, you could do something like I've done in the following snippet:
object Default {
val defaultMapping = mutableMapOf<KClass<*>, Any?>()
inline fun <reified T> get(): T? =
T::class.let {
defaultMapping[it] ?: it.java.constructors.getOrNull(0)?.let { c ->
try {
// NOTE: for now only parameterles constructor will work
c.newInstance()
} catch (e: Exception) {
e.printStackTrace()
null
}.also { v ->
defaultMapping[it] = v
}
} ?: run {
defaultMapping[it] = null
null
}
} as? T
inline fun <reified T> T.isDefault(): Boolean = defaultMapping[T::class] == this
}
inline fun <reified T> foo(bar: T? = Default.get()) {
if (bar?.isDefault() == true) println("bar: default is in use")
else println("bar: $bar")
}
fun main() {
foo<Any>()
foo(Default.get<Any>())
foo<Any>(null)
foo<Any>(bar = null)
foo(Any())
val a = Any()
foo(a)
foo(bar = a)
}
Note, that I have not polished the code in any way. Some parts are leftovers from several attempts (e.g. the part about the constructors.getOrNull(0)
) and I don't intend to improve that.
Also: This simple approach only works with default constructors (see it.newInstance()
) on the JVM. So that's no multi-platform solution in any way.
The result is something like
bar: default is in use
bar: default is in use
bar: null
bar: null
bar: java.lang.Object@41906a77
bar: java.lang.Object@4b9af9a9
bar: java.lang.Object@4b9af9a9
Again: Keep in mind, this is very simplistic, don't use that in production!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With