Kotlin: how to make a function call using the first argument's default value and passing a value for the second? - kotlin

I'd like to know how to call a function with default arguments when you want to specify the value of the second argument. In the simple example below I am showing that the addTwo() takes two arguments. The 'first' argument has a default value but the 'second does not. How would I call this function specifying that I want to use the default value for 'first' with the given value of 2 for 'second'?
Calling addTwo(2) throws an error.
fun main(args: Array<String>) {
var sum = addTwo(1,2) // works fine
var nextSum = addTwo(2) // ERROR: No value passed for parameter second
}
fun addTwo(first: Int = 0, second: Int): Int {
return first + second
}

This is an error because Kotlin does not know why you omitted a second parameter. The first can be defaulted, but not second. Therefore when you only passed in one argument it was for parameter first. The error message says exactly what the problem is:
no value passed for parameter second
You must call using named arguments for anything after the first defaulted parameter that you want to leave blank. For your case, this would be:
addTwo(second = 2) // first defaulted to 0
Had your defaulted parameters been in the other order, your call would be fine.
fun addTwo(first: Int, second: Int = 0): Int{
return first + second
}
addTow(2) // no error, second defaulted to 0
Had your data types been different for the two parameters, you would have seen a different less clear error letting you know the type of the first parameter (Int) was expected, not the type of the second (Date in the following example):
fun something(first: Int = 0, second: Date): Date { ... }
something(Date()) // ERROR: Type mismatch: inferred type is java.util.Date but kotlin.Int was expected
Note: You can run into the same issue with vararg:
Only one parameter may be marked as vararg. If a vararg parameter is not the last one in the list, values for the following parameters can be passed using the named argument syntax

Additional note: because of what you experienced, it is generally a best practice to make default arguments the last parameters in the list. Some languages even force this, such as Python (except that Python allows forced named arguments after defaults, since forcong you to call them by name is how you'd get around having parameters after default arguments anyway).

Related

How does kotlin determine which func to invoke when func overloads?

We know that kotlin allows us to use default parameters, but how does it determine which func to invoke when overload happens? like this below, the result is that the first test is invoked rather than the second, but why?
fun test() {
}
fun test(a: Int = 1) {
}
fun main() {
test()
}
The Kotlin language specification sets out rules for overload resolution.
First it states the general rule:
The compiler should first pick a number of overload candidates, which
form a set of possibly intended callables (overload candidate set,
OCS), and then choose the most specific function to call based on the
types of the function and the call arguments.
Then, later, in explaining how the most specific function is determined, it states:
For each candidate we count the number of default parameters not
specified in the call (i.e., the number of parameters for which we use
the default value). The candidate with the least number of
non-specified default parameters is a more specific candidate
So there you go. In your example the test() function without the default parameter will be chosen as it has a lesser number of non-specified default parameters, and is thus more specific.

Null check before using variable in function

I am wondering if there is a better way of null checking and assigning value like in this example
val result: Clazz? = if (variable == null) null else someFun(variable)
variable?.let(::someFun)
You can use the Kotlin scope function let .
let is often used for executing a code block only with non-null values. To perform actions on a non-null object, use the safe call operator ?. on it and call let with the actions in its lambda.
So in this case someFun is only called if variable is not null. Otherwise null is returned.
The longer form of this would be:
variable?.let { someFun(it) }
where it is the non-null value of variable. However:
If the code block contains a single function with it as an argument, you can use the method reference (::) instead of the lambda:
So we can shorten it to the
variable?.let(::someFun)
form

Kotlin "let{}" Doesn't Provide Smart Cast

Just learned Kotlin Nullable type and let{} function which replaces the if (xx != null) {} operation.
But one thing I am confused is that, we all know and I Think the Complier Should Know that when we use let{}, the variable/object who is calling this function is possiblly null, however the complier still requires me to add the safe call operator "?" after the variable name instead of providing Smart Cast like it does in if (xx != null) {}. Why?
My piece of code:
fun main() {
var number1: Int? = null
//val number2 = number1.let { it + 1 } ?: 10 //doesn't work, not quite "smart"
val number2 = number1?.let { it + 1 } ?: 10 //works, must have "?"
println(number1)
println(number2)
}
You've already got answers in the comments, but just to explain the ? thing...
Kotlin lets you make null-safe calls on nullable variables and properties, by adding ? before the call. You can chain this too, by doing
nullableObject?.someProperty?.someFunction()
which evaluates nullableObject, and if it's non-null it evaluates the next bit, otherwise the whole expression evaluates to null. If any part of the chain evaluates as null, the whole expression returns null.
So it has this short-circuiting effect, and you can use the elvis "if null" operator to create a default value if you can't evaluate the whole chain to a non-null result:
nullableObject?.nullableProperty?.someFunction() ?: defaultAction()
and once you introduce the null check in the chain, you have to add it for every call after that - it's basically propagating either the result of the previous bit, or the null it resolved to, so there's a null check at each step
The let block is just a scope function - you use it on a value, so you can run some code either using that value as a parameter or a receiver (a variable or this basically). It also has the side effect of creating a new temporary local variable holding that value, so if the original is a var it doesn't matter if that value changes, because your let code isn't referring to that variable anymore.
So it's useful for doing null checks one time, without worrying the underlying value could become null while you're doing stuff with it:
nullableVar?.let { it.definitelyIsNotNull() }
and the compiler will recognise that and smart cast it to a non-null type. An if (nullableVar != null) check can't guarantee that nullableVar won't be null by the time the next line is executed.

Could someone, please, explain me the implementation of the following "Kotlin Literal high order function"?

I am a newbie in Kotlin, I just started to learn it,
I get the following code example about literal/high order function:
fun myHigherOrderFun(functionArg: (Int)->String) = functionArg(5)
println ( myHigherOrderFun { "The Number is $it" })
prints "The Number is 5"
Which I have difficulty to understand: the function myHigherOrderFun get a lambda function as parameter but i can't understand, where is the (Int) input parameter? I see is passed in functionArg(5)... but i can't realize how is possible that?
Thanks in advance.
To start from the beginning, in Kotlin functions are first-class types, just like numbers and Strings and stuff.  So a function can take another function as a parameter, and/or return a function as its result.  A function which does this is called a ‘higher-order function’.
And that's what you have in your example!  The line:
fun myHigherOrderFun(functionArg: (Int)->String) = functionArg(5)
defines myHigherOrderFun() as a function which takes one parameter, which is itself a function taking a single Int parameter and returning a String.  (myHigherOrderFun() doesn't specify an explicit return type, so it's inferred to be a String too.)
The next line is probably where things are less clear:
println(myHigherOrderFun{ "The Number is $it" })
The first non-obvious thing is that it's calling myHigherOrderFun() with a parameter.  Because that parameter is a lambda, Kotlin lets you omit the usual (…), and use only the braces.
The other non-obvious thing is the lambda itself: { "The Number is $it" }. This is a literal function taking one parameter (of unspecified type).
Normally, you'd have to specify any parameters explicitly, e.g.: { a: Char, b: Int -> /* … */ }.  But if there's exactly one parameter, and you aren't specifying its type, then you can skip that and just refer to the parameter as it.  That's what's happening here.
(If the lambda didn't reference it, then it would be a function taking no parameters at all.)
And because the lambda is being passed to something expecting a function taking an Int parameter, Kotlin knows that it must be an Int, which is why we can get away without specifying that.
So, Kotlin passes that lambda to the myHigherOrderFun(), which executes the lambda, passing 5 as it.  That interpolates it into a string, which it returns as the argument to println().
Many lambdas take a single parameter, so it gets used quite a lot in Kotlin; it's more concise (and usually more readable) than the alternative.  See the docs for more info.

Can I use a name of the lambda as the parameter passed "outside of parentheses"?

I can write a lambda expression outside of parenthesis, but I cannot put it there by name. I have tried many ways:
val plus3: (Int,Int,Int)->Int = {a,b,c->a+b+c}
println(apply3(1,2,3){a,b,c->a+b+c}) // OK
println(apply3(1,2,3){plus3}) // Type mismatch. Required: Int, Found: (Int,Int,Int)->Int
println(apply3(1,2,3){(plus3)}) // Type mismatch. Required: Int, Found: (Int,Int,Int)->Int
println(apply3(1,2,3)plus3) // unresolved reference
println(apply3(1,2,3){plus3()}) // value captured in a closure
println(apply3(1,2,3){(plus3)()}) // value captured in a closure
What is the syntax to put a name there (outside of parenthesis)?
I don't know why, but in the documentation there is not a word on the theme. It says we could put lambda there, but not a word about a variable or constant that denotes that lambda.
I don't know why, but in the documentation there is not a word on the theme.
Yes, there is:
In Kotlin, there is a convention that if the last parameter to a function is a function, and you're passing a lambda expression as the corresponding argument, you can specify it outside of parentheses
plus3 is an identifier and not a lambda expression, so you can't specify it outside of parentheses.
The type of plus3 is (Int,Int,Int->Int). The same as of {a,b,c->a+b+c}. Look again at the messages that I am getting from Kotlin compiler.
You mean the error messages when you pass { plus3 }? By Kotlin rules { plus3 } is a lambda which ignores its argument (if any) and returns plus3. So the rule applies, and apply3(1,2,3){plus3} means the same as apply3(1,2,3,{plus3}).
It sees plus3 as Int.
Exactly the opposite: it expects to see an Int as the return value of the lambda and sees plus3 which is (Int,Int,Int) -> Int.
So, the problem here is not of the high philosophical nature, but seems pure syntactic.
That was exactly my point: the rule is purely syntactic, it's applied before the compiler knows anything about type or value of plus3, and so it doesn't know or care whether this value happens to be a lambda.
The rule could instead say
In Kotlin, there is a convention that if the last parameter to a function has a function type, you can specify it outside of parentheses
in which case apply3(1,2,3) plus3 would work. But it doesn't.
Placing a lambda expression outside of a function call's parentheses is the same as placing it inside the parentheses like this:
println(apply3(1, 2, 3, { a, b, c -> a + b + c }))
From here, we can simply assign the lambda to a val (as you have done) which results in:
val plus3: (Int, Int, Int) -> Int = { a, b, c -> a + b + c }
println(apply3(1, 2, 3, plus3))