I recently encountered a scenario where I wanted to be able to provide a nullable type argument to a function where the corresponding parameter was non-nullable with a default value. (My specific case was to do with processing an optional parameter when handling a HTTP request)
Consider this as an example:
fun foo(x: Long = 1) { ... }
fun bar(y: Long?): {
bar(y) // Error: "Required: Long \nFound: Long?"
}
My thought is that in the case where there is a provided default value, there should be a concise/succinct way of calling this function without writing a bunch of control flow.
The āneedā for a way to do this becomes more obvious when there is a number of these parameters (especially with non obvious defaults):
fun baz(a: Long = 1, b: Long = 200, c: Long = 40) { ... }
fun bar(y: Long?): {
val a: Long? = ...
val b: Long? = ...
val c: Long? = ...
// baz(a,b,c) doesn't compile so...
when {
a != null && b != null && c != null -> baz(a,b,c)
a != null && b != null -> baz(a = a, b = b)
a != null && c != null -> baz(a = a, c = c)
b != null && c != null -> baz(b = b, c = c)
a != null -> baz(a = a)
b != null -> baz(b = b)
c != null -> baz(c = c)
else -> baz()
}
}
Which as you can see, with even three parameters is rife with potential for making mistakes. (I think a chain of elvis operators would be just as bad)
The workaround Iām aware of is to do something like what follows below, but we lose the niceness of the defaults in the function signature, and is kinda verbose/ugly
fun foo(X: Long?) { // Or X: Long? = null as suggested by fatjoe79 below
val x = X? : 1
// The rest of the original function
}
fun bar(y: Long?): {
bar(y)
}
My proposal is a mechanism for allowing nullable arguments to be used for non-nullable parameters that have default values. I canāt think of a scenario where this would cause problems (Iām no expert though).
Some proposed mechanisms/ideas:
-
Have the compiler perform/implement the above workaround automatically when default arguments are present (Edit: Perhaps a different symbol for this behaviour when when defining the default parameter such as =?)
-
Allow Unit() to be passed instead null via an operator similar to the safe call (?.) or elvis operator (?: ) and do the same thing (My uninformed understanding is that Unit is kinda reserved for use by the language, this might be a case for that)
-
Only allow this functionality when ānamed argumentsā are used
Iām really interested in what people think of this so please point out any pitfalls you see or alternative mechanisms. Kotlin is very good for minimising overly verbose code, I think that there needs to be a way to provide arguments to a function when the data decides whether a parameter is available or not to take this all the way.