Type signature for Kotlin function with default parameters - kotlin

Let's say I have:
fun addInvoker(adder: () -> Int = ::add): Int{
return adder()
}
fun add(num1:Int = 1, num2:Int = 1): Int{
return num1 + num2
}
I get an error since ::add has two parameters, but the signature of addInvoker requires it to have zero parameters. However, if I change it to:
fun addInvoker(adder: (Int, Int) -> Int = ::add): Int{
return adder()
}
fun add(num1:Int = 1, num2:Int = 1): Int{
return num1 + num2
}
Then I can't invoke adder(), i.e. invoking add with its default arguments.
So, is there some way I can make ::add the default argument to invokeAdder but still invoke add with adder(), thus invoking it with the default args?

You can make a lambda of your add which will be no-argument function and will call add with its default arguments: { add() }.
Complete code:
fun addInvoker(adder: () -> Int = { add() }): Int {
return adder()
}
fun add(num1: Int = 1, num2: Int = 1): Int {
return num1 + num2
}
In Kotlin, functions with default arguments have no special representation in the type system, so the only option is to make wrappers passing only part of arguments to them:
val add0: () -> Int = { add() }
val add1: (Int) -> Int = { add(num1 = it) }
val add2: (Int) -> Int = { add(num2 = it) }

Related

How to use parameters inside a block when defining an extension function?

val test: Int.(String) -> Int = {
plus((this))
}
When defining this type of extension function, how can I use arguments( Here, the argument of type String) inside the block?
When defining extension functions at the same time as declaration like this, can only this be used?
You can access it using it:
val test: Int.(String) -> Int = {
println("this = $this")
println("it = $it")
42
}
fun main() {
println("result = " + 1.test("a"))
}
This will output
this = 1
it = a
result = 42
An alternative is to introduce a lambda-parameter:
val test: Int.(String) -> Int = { s ->
println("this = $this")
println("s = $s")
42
}
fun main() {
println("result = " + 1.test("a"))
}
This will output
this = 1
s = a
result = 42

Test closure of an extension function in Kotlin

Suppose we have the following code:
#ExperimentalCoroutinesApi
fun ProducerScope<DownloadableDataDto<out User>>.findInteresting(input: ReceiveChannel<DownloadableDataDto<out User>>,
communitiesCount: Int,
userCountMap: MutableMap<User, Int> = ConcurrentHashMap()) = createProducer(input) {
if (userCountMap.compute(it.data!!) { _, value ->
if (value == null) 1 else value + 1
} == communitiesCount) send(it)
}
This code checks if a user is a part of all of the communitiesCount communities. But this logic is enclosed inside a createChannel() higher order function, which I would not want to test at the moment. Is there a way to test only the internals? I assume I could probably extract that to a separate function as well, right?
And if I do it that way, let's say we have this instead:
#ExperimentalCoroutinesApi
fun ProducerScope<DownloadableDataDto<out User>>.findInteresting(input: ReceiveChannel<DownloadableDataDto<out User>>,
communitiesCount: Int,
userCountMap: MutableMap<User, Int> = ConcurrentHashMap()) = createProducer(input) {
sendIfInteresting(it, communitiesCount, userCountMap)
}
#ExperimentalCoroutinesApi
private suspend fun ProducerScope<DownloadableDataDto<out User>>.sendIfInteresting(userDto: DownloadableDataDto<out User>,
communitiesCount: Int,
userCountMap: MutableMap<User, Int>) {
if (userCountMap.compute(userDto.data!!) { _, value ->
if (value == null) 1 else value + 1
} == communitiesCount) send(userDto)
}
How would I mock the send(userDto) call? I can mock the ProducerScope object, but how would I call the real sendIfInteresting() method?

List<List<Char>> + List<Char> = List<Any>?

I have a below code which works.
class ListManipulate(val list: List<Char>, val blockCount: Int) {
val result: MutableList<List<Char>> = mutableListOf()
fun permute(sequence: List<Int> = emptyList(), start: Int = 0, count: Int = blockCount) {
if (count == 0) {
result.add(constructSequence(sequence))
return
}
for (i in start .. list.size - count) {
permute(sequence + i, i + 1, count - 1)
}
}
private fun constructSequence(sequence: List<Int>): List<Char> {
var result = emptyList<Char>()
for (i in sequence) {
result += list[i]
}
return result
}
}
However, when I change the result from MutableList to normal List, i.e.
var result: List<List<Char>> = emptyList()
// ...
result += constructSequence(sequence)
I got this error Type mismatch. Require: List<List<Char>>; Found: List<Any>
The full code as below
class ListManipulate(val list: List<Char>, val blockCount: Int) {
var result: List<List<Char>> = emptyList()
fun permute(sequence: List<Int> = emptyList(), start: Int = 0, count: Int = blockCount) {
if (count == 0) {
result += constructSequence(sequence)
return
}
for (i in start .. list.size - count) {
permute(sequence + i, i + 1, count - 1)
}
}
private fun constructSequence(sequence: List<Int>): List<Char> {
var result = emptyList<Char>()
for (i in sequence) {
result += list[i]
}
return result
}
}
Why result + constructSequence(sequence) would result in List<Any> instead of List<List<Char>>?
Is there a way I could still use the normal List> and not the mutable list?
CTRL + click on the + in IDEA, you'll see that it takes you to the following function:
/**
* Returns a list containing all elements of the original collection and then all elements of the given [elements] collection.
*/
public operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T> {
/* ... */
}
Which means that you add all the individual elements of elements to the receiver. That is, you'll add all T's to the List<List<T>>. Since List<T> is not T, you'll get List<Any> as a result.
The problem is that += is overloaded. If it sees an Iterable, Array or Sequence it behaves differently. You have to explicitly use plusElement() to achieve the behaviour you intend.
Consider the following code.:
class ListManipulate(val list: List<Char>, val blockCount: Int) {
var result: List<List<Char>> = emptyList()
fun permute(sequence: List<Int> = emptyList(), start: Int = 0, count: Int = blockCount) {
if (count == 0) {
result = result.plusElement(constructSequence(sequence))
return
}
for (i in start..list.size - count) {
permute(sequence + i, i + 1, count - 1)
}
}
private fun constructSequence(sequence: List<Int>): List<Char> =
List(sequence.size, { i -> list[sequence[i]] })
}
PS: I also took the liberty to update your constructSequence() to something more concise.
Btw: += uses addAll internally.
/**
* Returns a list containing all elements of the original collection and then all elements of the given [elements] collection.
*/
public operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T> {
if (elements is Collection) {
val result = ArrayList<T>(this.size + elements.size)
result.addAll(this)
result.addAll(elements)
return result
} else {
val result = ArrayList<T>(this)
result.addAll(elements)
return result
}
}
Side note: you can also do:
result.toMutableList().add(constructSequence(sequence))
It is fine to return a MutableList, the only difference really is that the List interface doesnt have the manipulation methods. Internally both are represented by an ArrayList
#SinceKotlin("1.1")
#kotlin.internal.InlineOnly
public inline fun <T> List(size: Int, init: (index: Int) -> T): List<T> = MutableList(size, init)

How to understand a fun with = in Kotlin?

I know a standard fun just like Code 0.
The Code 1 is a sample code from webpage, I can't understand completely the
fun convertFromDomain(forecast: ForecastList) = with(forecast) {...}
Why is the symbol = added to the fun? and is the return value of the fun convertFromDomain unit ?
Code 0
fun My(forecast: ForecastList):Boolean {
...
return true;
}
Code 1
data class ForecastList(val id: Long, val city: String, val country: String, val dailyForecast: List<Forecast>) {
val size: Int
get() = dailyForecast.size
operator fun get(position: Int) = dailyForecast[position]
}
data class Forecast(val id: Long, val date: Long, val description: String, val high: Int, val low: Int,
val iconUrl: String)
fun convertFromDomain(forecast: ForecastList) = with(forecast) {
val daily = dailyForecast.map { convertDayFromDomain(id, it) }
CityForecast(id, city, country, daily)
}
Block body
Consider this function:
fun sum(a: Int, b: Int): Int {
return a + b
}
The behaviour is defined in a block body. It has an explicit return type (Int) and an explicit return statement. Both are mandatory here. If you don't specify a return type explicitely it will be Unit by default and since the inferred type of a + b is Int it won't compile.
Expression body
If you write it like this
fun sum(a: Int, b: Int) = a + b
you don't need to specify the return type because it can be inferred from the expression.You don't need a return statement either because the last expression is returned. What follows the = sign is called an expression body.
So, both functions do the same thing. The second one is only written more concise.
Note
A common mistake is to use them both at once like this:
fun sum(a: Int, b: Int) = { a + b }
What this would do becomes clear, if you specify the returned type explicitely:
fun sum(a: Int, b: Int): () -> Int = { a + b }
You would actually return a lambda of type () -> Int which is surely not what you want.
A function has usually the following form in kotlin:
fun name([parameters])[: return_type] {
// function-body
}
e.g.
fun doubleTheValue(number: Int): Int {
return number * 2
}
If your function-body is just a single-expression, you can use a shorter version of the function declaration
fun name([parameters])[: return_type] = [expression]
e.g.
fun doubleTheValue(number: Int): Int = nummber * 2
fun doubleTheValue(number: Int) = nummber * 2 // type can also be inferred
So it's nothing special, just a shorter version of a function declaration.
Traditional way to define a function is just like what you write in Code 0, which consists of function name, parameters, return type and the block body. In Kotlin, function can be defined with an expression body and the return type can be inferred from the expression body.
Suppose there is a function which convert Boolean to Int, in traditional way:
fun Boolean.toInt(): Int {
return if (this) 1 else 0
}
It can be simplified to:
fun Boolean.toInt() = if (this) 1 else 0
where the return type is inferred as Int because 1 and 0 are both Int which will be returned from the expression if (this) 1 else 0.

Kotlin: Function-param implementation in a body of a caller

fun lazyProperty(initializer: () -> Int): Int {
val result: Lazy<Int> = lazy(initializer)
return result.value
}
fun main(args: Array<String>) {
// 1.
val bar: Int = lazyProperty({ 1 + 1 })
// 2.
val foo: Int = lazyProperty() {
42
}
println("bar $bar, foo: $foo")
}
I recently stumbled over the syntax of calling a function in Kotlin and I just don't get it:
the fist option is clear - it's a lambda, but the second one looks not like a usual syntax of calling a function with the required parameter. The brackets where normally params should be placed are empty and instead the function-parameter comes in the body of the caller! How is it possible and what for is it needed?
This is another valid way of passing a lambda. According to the docs:
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:
lock (lock) {
sharedResource.operation()
}
You can choose whichever approach you prefer.
This is just convention. If the last param of a function is a function, you can pass the lambda outside the parentheses. In your case you have the following options:
val bar: Int = lazyProperty({ 1 + 1 })
val bar: Int = lazyProperty() { 1 + 1 }
val bar: Int = lazyProperty { 1 + 1 }
All three options are the same.
If your function would have a second parameter (at first position), than the calls could look like this:
fun lazyProperty(x: Int, initializer: () -> Int): Int {...}
val bar: Int = lazyProperty(7, { 1 + 1 })
val bar: Int = lazyProperty(7) { 1 + 1 }
If your function would have a second parameter (at second position), than the calls could look like this:
fun lazyProperty(initializer: () -> Int, x: Int): Int {...}
val bar: Int = lazyProperty({ 1 + 1 }, 7)
So always try to keep the Lambda at the last position of your function.