Is the a way to use the default value of a non-nullable parameter when null is passed as an argument? - kotlin

I looking for a way to have default values take the place of nulls when passed as arguments. My motivation is purely to reduce the amount of code written (I want to avoid having overloaded functions/constructors or manual 'if null' checks)
My use case is within a Spring RestController, I want default values of a method called by the controller to be used without needing to state those default values outside the function.
I thought perhaps that using named parameters might provide this functionality but my experiments show otherwise. Perhaps there is a way with the elvis operator?
Example Code:
fun someFunction(first: Long = 1, second: Int = 2 ) {
// Do something
}
#GetMapping
fun someEndpoint(#RequestParam("first") firstParam: Long?):ResponseEntity<Any> {
someFunction(firstParam) // Attempt 1: "Required: Long\n Found: Long?
someFunction(first = firstParam) // Attempt 2: Same error
}
Hopefully you can help

There aren't any specific language features that would do this for you, the default argument mechanism isn't connected to nullability in any way.
However, you can achieve this in a more manual fashion by making your parameters nullable, and immediately substituting default values inside the function if they're null:
fun someFunction(first: Long? = null, second: Int? = null) {
val actualFirst: Long = first ?: 1
val actualSecond: Int = second ?: 2
// Do something with actualFirst and actualSecond
}

The #RequestParam annotation has a default value option named "defaultValue".
you can use it like so:
#GetMapping
fun someEndpoint(#RequestParam(name = "first", defaultValue = "1") firstParam: Long):ResponseEntity<Any> {
someFunction(firstParam) // firstParam equals to 1 if null was passed to the endpoint
}

Related

is there any way I send a nullable Function<T,R> as parameter in Kotlin?

I am trying to use the public interface Function (as I learned it in Java) in Kotlin.
For this I created my method
fun foo(input: List<String>, modifier1: Function<List<String>>? = null){
}
as far I remember here I should be able to do modifier1.apply(input)
but seems like it is not possible (it is possible to do modifier1.apply{input} though)
Reading more about it I found this:
Kotlin: how to pass a function as parameter to another?
So I changed my method signature to this:
fun foo(input:String, modifier2: (List<String>) -> (List<String>){
}
Here I am able to do modifier2(input)
and I can call foo this way
service.foo(input, ::myModifierFunction)
where
fun myModifierFunction(input:List<String>):List<String>{
//do something
return input
}
So far this seems possible but it is not acceptable to have the function reference as nullable, is there any way I can do that? or use Function ?
You were using kotlin.Function instead of java.util.function.Function in your first example. Note that the latter takes 2 generic types: 1 for the incoming parameter and 1 for the resulting one.
The apply method you saw is the default Kotlin one: apply, not the one of Java's Function-interface.
If you really want to have the Java-function as nullable type the following should work:
fun foo(input: List<String>, modifier1: java.util.function.Function<List<String>, List<String>>? = null) {
modifier1?.apply(input) ?: TODO("what should be done if there wasn't passed any function?")
}
Kotlin variant for the same:
fun foo(input: List<String>, modifier1: ((List<String>) -> List<String>)? = null) {
modifier1?.invoke(input) ?: TODO("what should be done if there wasn't passed any function?")
}
Maybe also a default function, such as { it } instead of null might better suite your needs? (Java variant would be Function.identity()):
// java modifier1 : Function<List<String>, List<String>> = Function.identity()
// kotlin modifier1 : (List<String>) -> List<String> = { it }
You can make the reference nullable simply with ? — the only wrinkle is that the whole function type needs to be in parens first:
fun foo(input: String, modifier2: ((List<String>) -> List<String>)? = null) {
}
As required, modifier2 is optional; if specified, it may contain null, or it may contain a function taking and returning a list of strings.
As mentioned in another answer, kotlin.Function is not the same as java.util.function.Function — though in practice you shouldn't need to refer to either directly, as the -> notation is simpler.
If you want to pass in a function that takes List<String> as its parameter and returns nothing meaningful, the type for you is Function1<List<String>, Unit>. The method name for invoking a function is invoke(), which you could also do with just regular parentheses, if it wasn't nullable. All in all, your code could look something like this:
fun foo(input: List<String>, modifier1: Function1<List<String>, Unit>? = null) {
modifier1?.invoke(input)
}
The 1 in the typename of Function1 means that it's a one parameter function, there's also Function0, Function2, etc.
The Function type on its own is not something you can use to call that function, as it's an empty marker interface. All functions implement this regardless of how many parameters they have.

Kotlin multiple variable let, using the previous variables in the next let

I want to be able to have multiple let and the next let is able to use the previous variable only if its not null. The reason I want this is because I want only one :? for all the lets. Is this possible?
Example on how I want it to be:
fun example() {
firstVariable?.let a -> &&
exampleFunction(a, 3)?.let { a, b ->
// Use a and b freely since they are not null and not optionals
} ?: run {
// Runs if either one of the let is failing
}
}
// a is NOT optional
fun exampleFunction(a: Int, b: Int?): Int? {
if (b == null) {
return null
}
return a + b
}
Stupid example, but its just to show what I need... I want to check if the first variable is null AND to run a function that returns an optional with a non-optional parameter which is the first variable - if either of these fail, I want to run something else.
I know how to do this without let, but I am wondering if it's possible or planned to be able to do this? (It's possible in Swift).
How to do it in Swift:
// First check a, then use a in the same expression if its validated
if let a = firstVariable,
let b = exampleFunction(a) {
// Use a and b as non-optionals
} else {
// a or b failed
}
You propably missunderstood how let works. I am going to explain a bit. In short the desired behaviour is not possible in kotlin or at least you can not idiomatically emulate it without any drawbacks whatsoever.
I don't know swift but it seems as if the let used there is some sort of syntax construct offered by the language itself. It allows you to define a variable with some local scope and can be chained (like the short circuiting &&).
In Kotlin however let is just a normal function.
See the documentation. It's basically nothing more than
fun <T, R> T.let(block: (T) -> R): R = block(this)
It allows to call a function with a normal parameter as a function with a receiver type.
The actual null check is done with the ?. operator.
It takes an optional/nullable value as left hand side operand and either short circuits returning null or call the function on the right hand side with the non-null left hand side as receiver type. let is just one possible function to call here.
The similar ?: operator takes an optional/nullable LHS operand and returns this value if it is not null or it evaluates the expression on the RHS.
One way to get those variables defined is by nesting lets:
firstVariable?.let{a -> exampleFunction(a, 3)?.let{b -> a + b}} ?: run{}
where a + b is just an example of using both values. This however becomes unhandy if it's longer than one line. If you still want to define local variables you can create a block with run and use jump statements on the right side of ?:
run {
val a = firstValue ?: return#run null
val b = exampleFunction(a, 3) ?: return#run null
return#run a + b
} ?: run{}
While the above code looks really ugly with all those return#run null repititions there might be ways to reduce the amount of repeating code e.g. by using a anonymous function (to get rid of the #run part) or return Unit and safe the last value with some side-effect operation. (to get rid of the null and the last return statement)
You could benefit on Kotlin and write sot of extension function for your case. vararg as we dont know how many variables we want to pass, then check if all of them are not null and if so, return all of them. If any of the vars will be null, then nothing happens.
fun <T: Any> multipleLetCheck(vararg variables: T?, block: (List<T>) -> Unit): Unit? {
return if (variables.all { variable -> variable != null }) {
block(variables.filterNotNull())
} else {
null
}
}
// usage
multipleLetCheck(firstVariable, 3){ (firstVariable, secondVariable) ->
// work with firstVariable and secondVariable
} ?: run {
}

Passing a parameter to a function only if not null

I need to pass a nullable parameter to a function that only accepts non nullable objects, but has a default value defined.
Currently I'm using a let:
fun myFun(a:String = "qqq"): Whatever {...}
val myString:String? = getNullableString()
val myFunResult = myString.?let{myFun(it)}?:myFun()
This is verbose and it is no more possible when there's more than an optional parameter.
I'd need something like
val myFunResult = myFun(myString?:default)
Is there a pratical way to do this?
If you don't want to repeat the default value outside of the function (I wouldn't) you are going to have to do some kind of conditional check. Personally speaking, I find the let expression hard to read when scanning code, and would probably just go with an if. Keep in mind that in Kotlin, if is an expression:
if(myString == null) myFun() else myFun(myString)
You could allow passing nullable values as parameters into your function, change named default value to null and set the actual default value inside the function's body:
fun myFun(a: String? = null) {
val a = a ?: DEFAULT_VALUE
// rest of the function
}
val myFunResult = myFun(myString)
Since you mentioned you can't change the initial function you are calling. Writing a new function to call the initial function might be a more readable approach.
fun myFun(a:String = "qqq"): Whatever {...}
fun myNewFun(a:String? = null): Whatever = if(a == null) myFun() else myFun(a)

Is there an elegant kotlin way of convincing the compiler that a nullable field to which I just assigned a real value can't be null anymore?

I have read that using !! should generally be avoided.
Is there a way to write the following code in a more elegant way without having to add something like obsolete null checks and duplicated or dead blocks of code?
class A(var field: Thing?) {
fun getField(): Thing {
if (field == null) {
field = Thing()
}
return field!!
}
}
Also I don't understand why the compiler requires the !!-'pray-this-isn't-null-operator' to be satisfied in this scenario.
EDIT: Consider that it is important to me that a potential solution uses lazy initialization if the field is null!
Problem
As Enzokie already mentioned in the comments, another thread could have changed field after the null check. The compiler has no way of knowing that, so you have to tell it.
class A(var field: Thing?) {
fun getField(): Thing {
if (field == null) {
field = Thing()
}
// another thread could have assigned null to field
return field!! // tell the compiler: I am sure that did not happen
}
}
Solution (Eager)
In you particular case it would be a good idea to use a parameter f (you could name it "field" too, but I avoided that for clarity) in the constructor (without val/var) and afterwards assign it to a property field to which you assign either f or a new instance of Thing.
This can be expressed really concise with the Elvis operator :? which takes the left hand side if not null and the right hand side of the expression otherwise. So, in the end field will be of type Thing.
class A(f: Thing?) {
val field = f ?: Thing() // inferred type Thing
}
Solution (Lazy)
Since it was mentioned by gidds, if you need to initialize field lazyly you could do it like this using delegated properties:
class A(f: Thing?) {
val field by lazy {
f ?: Thing() // inferred type Thing
}
}
The call site does not change:
val a = A(null) // field won't be initialized after this line...
a.field // ... but after this
How about this?
class A(field: Thing?) {
private lateinit var field: Thing
init {
field?.let { this.field = it }
}
fun getField(): Thing {
if (!this::field.isInitialized) {
field = Thing()
}
return field
}
}
When you define a field, you actually define a variable plus two accessor methods:
val counter: Integer = 0
It is possible to customize the accessor methods by writing this instead:
val n = 0
val counter: Integer
get() = n++
This will execute the n++ each time you access the counter field, which therefore returns different values on each access. It is uncommon and unexpected but technically possible.
Therefore the Kotlin compiler cannot assume that two accesses to the same field return the same value twice. Usually they do, but it is not guaranteed.
To work around this, you can read the field once by copying it into a local variable:
fun count() {
val counter = counter
println("The counter is $counter, and it is still $counter.")
}

How to pass nullable type into function that takes a non null type?

Is this possible if I do a null check before passing? For example:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
if (num != null) doSomething(num)
}
fun doSomething(number: Int) {
...
}
I don't understand why the compiler won't allow me to pass a nullable even though I check that it's not null first. Can anyone explain?
NOTE: starting from compiler version 1.0 beta the code in question works as is
The compiler can tell if the variable is mutated between check and use, at least in case of local variables like in this question, and in some other cases. See Jayson's answer for details.
http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-keyword--in-conditions says
The compiler tracks the information about the [null] check ... this only works where b is immutable (i.e. a local val or a member val which has a backing field and is not overridable), because otherwise it might happen that b changes to null after the check.
So something like this should work:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
fun doSomething(number: Int) {
...
}
Of course, it would be nicer to rewrite "stuff happens" in such a way that you could make num into a val in the first place.
In current Kotlin (1.0 beta or newer) you do not have this issue anymore. Your code would compile. A local variable that is val or var can safely Smart Cast since the compiler can determine if the value could have mutated or not (on another thread for example).
Here is an excerpt from another Stack Overflow question that covers more aspects of nullability and Kotlin's operators for dealing with them.
More about null Checking and Smart Casts
If you protect access to a nullable type with a null check, the compiler will smart cast the value within the body of the statement to be non nullable. There are some complicated flows where this cannot happen, but for common cases works fine.
val possibleXyz: Xyz? = ...
if (possibleXyz != null) {
// allowed to reference members:
possiblyXyz.foo()
// or also assign as non-nullable type:
val surelyXyz: Xyz = possibleXyz
}
Or if you do a is check for a non nullable type:
if (possibleXyz is Xyz) {
// allowed to reference members:
possiblyXyz.foo()
}
And the same for 'when' expressions that also safe cast:
when (possibleXyz) {
null -> doSomething()
else -> possibleXyz.foo()
}
// or
when (possibleXyz) {
is Xyz -> possibleXyz.foo()
is Alpha -> possibleXyz.dominate()
is Fish -> possibleXyz.swim()
}
Some things do not allow the null check to smart cast for the later use of the variable. The example above uses a local variable that in no way could have mutated in the flow of the application, whether val or var this variable had no opportunity to mutate into a null. But, in other cases where the compiler cannot guarantee the flow analysis, this would be an error:
var nullableInt: Int? = ...
public fun foo() {
if (nullableInt != null) {
// Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time"
val nonNullableInt: Int = nullableInt
}
}
The lifecycle of the variable nullableInt is not completely visible and may be assigned from other threads, the null check cannot be smart cast into a non nullable value. See the "Safe Calls" topic below for a workaround.
Another case that cannot be trusted by a smart cast to not mutate is a val property on an object that has a custom getter. In this case the compiler has no visibility into what mutates the value and therefore you will get an error message:
class MyThing {
val possibleXyz: Xyz?
get() { ... }
}
// now when referencing this class...
val thing = MyThing()
if (thing.possibleXyz != null) {
// error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter"
thing.possiblyXyz.foo()
}
read more: Checking for null in conditions
You can use let to simplify the code. The kotlin scope function introduces a local variable in the context of "num". No need to declare temporary variable numVal.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
num?.let{
doSomething(it)
}
}
Which works same as below but simpler and cleaner.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
Use can use Scoping function let or apply along with null safe operator ?.
fragmentManager?.let{
viewPager.adapter = TasksPagerAdapter(it)
}
This way you can pass a nullable type to a non-nullable type parameter