I don't see any examples of how to use tuples in Kotlin.
The errors i get on the first line (method definition) is "unresolved reference: a" and "expecting member declaration" for Int...
private fun playingAround : Pair<out a: Int, out b: Int> {
if(b != 0) {
b = a
a = a * 2
} else {
b = a
a = a * 3
}
return Pair(a, b)
}
About the logic: b is 0 in the beginning and a has a random value.
From the second call on, we go into the else logic.
i don't feel the official doc is enough: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/index.html. I did try also without the ":" after the method name like the official doc seems to imply
-same problem
You are using incorrect syntax. It should be something like this:
private fun playingAround(a: Int, b: Int): Pair<Int, Int> {
val x: Int
val y: Int
if (b != 0) {
y = a
x = a * 2
} else {
y = a
x = a * 3
}
return Pair(x, y)
}
Note that a and b are method parameter values which cannot be reassigned, so you need variables x and y to store the result.
You can write this with much shorter syntax though:
private fun playingAround(a: Int, b: Int) = if (b != 0) Pair(a * 2, a) else Pair(a * 3, a)
Please have a look at the functions chapter of the kotlin reference and/or play around with the Kotlin koans to get familiar with Kotlin (or if, by any means, reading grammar is your favorite, have a look at the function declaration grammar instead; if you do not get what's written there, no problem. Start with the tutorials/reference instead).
One of the solutions could look like this:
private fun playingAround(a: Int, b: Int) = b.let {
if (it != 0) a * 2
else a * 3
} to a
or if you meant, that you actually want to pass a pair, then maybe the following is better:
private fun playingAround(givenPair: Pair<Int, Int>) = givenPair.let { (a, b) ->
b.let {
if (it != 0) a * 2
else a * 3
} to a
}
It's hard to really know what you wanted to accomplish as you didn't really specify what that is.
Extension function instead? For completeness:
private fun Pair<Int, Int>.playingAround() = let { (a, b) ->
b.let {
if (it != 0) a * 2
else a * 3
} to a
}
and of course: you do not need to use let, nor to use to, nor to use destructuring declarations, etc. There are just some of many possible solutions.
You can rewrite your code as the following:
private fun playingAround(a: Int, b: Int) : Pair<Int, Int> {
val tempA: Int
val tempB: Int
if(b != 0) {
tempB = a
tempA = a * 2
} else {
tempB = a
tempA = a * 3
}
return Pair(tempA, tempB)
}
And using Destructuring Declarations you can write the following:
val (a, b) = playingAround(1, 2)
Your function syntax is not correct. I suggest to study the documentation first.
To make this a bit more Kotlin-idiomatic, use if as an expression:
private fun playingAround(a: Int, b: Int): Pair<Int, Int> =
if (b != 0) {
Pair(a * 2, a)
} else {
Pair(a * 3, a)
}
Related
I have the following simple class hierarchy.
abstract class B {
abstract val o : Int
}
class D1 (m: Int, n: Int) : B() {
override val o = m + n
}
class D2 (m: Int, n: Int) : B() {
override val o = m * n
}
I need a "factory function" f that gives me instances of D1 or D2 by calling it as f<D1>() or f<D2>() with hard coded parameters, say 3 and 4. The following doesn't work but illustrates what I need:
// won't compile; just demonstrates what I need
fun < T : B > f () : T {
return T(3, 4) // i. e. return T.constructor(m, n)
}
How to best accomplish this? Any DRY way is fine as long I don't have to repeat 3, 4 all over my code when I instantiate D1 or D2
The only way to do it is via reflection and reified type parameter:
inline fun <reified T : B> f(m: Int = 3, n: Int = 4): T {
val constructor = T::class.constructors.first {
it.parameters.size == 2 &&
it.parameters.all { param -> param.type == Int::class }
}
return constructor.call(m, n)
}
Here's an alternate way without reflection, but you have to manually type out a line for each class you want to handle.
inline fun <reified T : B> f(): T{
val m = 3
val n = 4
return when (T::class) {
D1::class -> D1(m, n)
D2::class -> D2(m, n)
else -> error("Unsupported type ${T::class}")
} as T
}
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?
Do you know if there is a shortcut for:
if (x == null) null else f(x)
For Java Optional you can just do:
x.map(SomeClass::f)
Kotlin utilizes its own approach to the idea of Option, but there're map, filter, orElse equivalents:
val x: Int? = 7 // ofNullable()
val result = x
?.let(SomeClass.Companion::f) // map()
?.takeIf { it != 0 } // filter()
?: 42 // orElseGet()
I ended up writing a full comparison here:
You can use let in this case, like this:
fun f(x : Int) : Int{
return x+1
}
var x : Int? = 1
println(x?.let {f(it)} )
=> 2
x = null
println(x?.let {f(it)} )
=> null
and as #user2340612 mentioned, it is also the same to write:
println(x?.let(::f)
You can try with let (link to documentation):
x?.let(SomeClass::f)
Example
fun f(n: Int): Int {
return n+1
}
fun main(s: Array<String>) {
val n: Int? = null
val v: Int? = 3
println(n?.let(::f))
println(v?.let(::f))
}
This code prints:
null
4
Suppose, I have a class of the following structure
class Test {
var a: Double? = null
var b: Double? = null;
var c: Double? = null;
}
a and b are set somewhere else, and c should be calculated as a / b or null if at least one of the arguments is null. Is there an easy way to achieve this in Kotlin?
I has to do it the following way now:
fun calculateValues() {
...
val a = test.a
val b = test.b
if (a != null && b != null)
test.c = a / b
...
}
class Test {
var a: Double? = null
var b: Double? = null
val c: Double? // It should be val as it is readonly
get() {
// This is need as a & b are mutable
val dividend = a
val divisor = b
if (dividend == null || divisor == null)
return null
return dividend / divisor
}
}
test.apply {
c = if (a==null || b==null) null else a/b
}
Of course that can be included as a getter of c (which in turn avoids storing c as a field):
class Test {
var a: Double? = null
var b: Double? = null
var c: Double? = null
get() = if (a==null || b==null) null else a/b
}
If Test is not a class of yours, you can always use an extension function:
fun Test.updateC() {
c = if (a==null || b==null) null else a/b
}
and that can then be called on a Test instance just like any other function of the Test class: test.updateC()
If you need to make sure about nullability at the time of computing a/b, you should use temporary variables as indicated in #Joshua answer below. Or also read the following Kotlin discussion: https://discuss.kotlinlang.org/t/kotlin-null-check-for-multiple-nullable-vars/1946/11 and ticket: https://youtrack.jetbrains.com/issue/KT-20294
I especially like the reusable solution with a function:
fun notNull(vararg args: Any?, action: () -> Unit) {
when {
args.filterNotNull().size == args.size -> action()
}
}
which can be used then as:
c = null
notNull(a, b) { c = a/b }
As the logic is outside of Test class I don't find the problem of checking nullability before making the operation. Anyway, if else is also an expressión in Kotlin so you could do the following:
val a = test.a
val b = test.b
t.c = if (a != null && b != null) a / b else null
is there any better way to write generic swap function in kotlin other than java way described in How to write a basic swap function in Java.
Is there any kotlin language feature which can make generic swap function more concise and intuitive?
No need a swap function in Kotlin at all. you can use the existing also function, for example:
var a = 1
var b = 2
a = b.also { b = a }
println(a) // print 2
println(b) // print 1
If you want to write some really scary code, you could have a function like this:
inline operator fun <T> T.invoke(dummy: () -> Unit): T {
dummy()
return this
}
That would allow you to write code like this
a = b { b = a }
Note that I do NOT recommend this. Just showing it's possible.
Edit: Thanks to #hotkey for his comment
I believe the code for swapping two variables is simple enough - not to try simplifying it any further.
The most elegant form of implementation IMHO is:
var a = 1
var b = 2
run { val temp = a; a = b; b = temp }
println(a) // print 2
println(b) // print 1
Benefits:
The intent is loud and clear. nobody would misunderstand this.
temp will not remain in the scope.
Kotlin encourages the use of immutable data when possible (such as using val instead of var). This greatly reduces the change for subtle bugs, since it's possible to reason more soundly about code if values don't change.
Swapping two values is very much the opposite of immutable data: Did I mean the value of a before or after the swap?
Consider rewriting your code in the following immutable way:
val a = 1
val b = 2
val (a2, b2) = b to a
This works by making use of destructuring declarations, along with the built-in to extension function that creates a Pair.
That is a good usage for with:
var a = 1
var b = 2
with(a) {
a = b
b = this
}
println(a) // 2
println(b) // 1
Very simple, fast and elegant solution:
var a = 1
var b = 2
val (b0, a0) = a swap b
a = a0
b = b0
infix fun <A> A.swap(second: A): Pair<A, A> = second to this
prefer a=b.apply {b=a} for swapping the elements.
If we want to perform some operation on the variable inside the lambda, then go for
a = b.also {someFun(it)}
If you're swapping array values in place, from a code readability perspective, it was helpful for me to add an extension function swapInPlace
fun <T> Array<T>.swapInPlace(i1: Int, i2: Int){
this[i1] = this[i2].also{ this[i2] = this[i1] }
}
fun main(){
val numbers = arrayOf(2, 1)
//This is easier for me to read...
numbers.swapInPlace(0, 1)
//Compared to this
numbers[0] = numbers[1].also{ numbers[1] = numbers[0] }
}
I have something interesting for all:
Why just numbers. We can swap anything with a generic class and a generic function
class Mutable<T>(var value: T) {
override fun toString() = value.toString()
/**
infix fun swapWith(other: Mutable<T>) {
value = other.value.also { other.value = value }
}
**/
}
fun <T> swap(num1: Mutable<T>, num2: Mutable<T>) {
num1.value = num2.value.also { num2.value = num1.value }
}
fun main() {
val num1 = Mutable(4)
val num2 = Mutable(6)
println("Before Swapping:-\n\tNumber#1 is: $num1\n\tNumber#2 is: $num2\n")
//calling way of class method is not like usual swap function
//num1 swapWith num2
//calling the actual swap function.
swap(num1, num2)
println("After Swapping:-\n\tNumber#1 is: $num1\n\tNumber#2 is: $num2\n")
}
class Mutable is a generic class here which can contain any type of data into it.
I overridden toString() method to directly accessing the value attribute by just calling the object.
fun swap is a true swap function for kotlin that gives you the call by reference's demo too.
operator swapWith also works as swap function, which is a part of Mutable class. I have commented that part because the calling way for the operator is not like the way we are used to with.
Output:
Before Swapping:-
Number#1 is: 4
Number#2 is: 6
After Swapping:-
Number#1 is: 6
Number#2 is: 4
I have different approach.
You can keep your two values in a Pair. Then you can do this:
fun <T> swap(pair: Pair<T, T>): Pair<T, T> {
return Pair(pair.second, pair.first)
}
and you use it like this:
var pairOfInts = Pair(1, 2)
println("first: ${pairOfInts.first}") // prints 1
println("second: ${pairOfInts.second}") // prints 2
pairOfInts = swap(pairOfInts)
println("first: ${pairOfInts.first}") //prints 2
println("second: ${pairOfInts.second}") //prints 1
In order to use Kotlin List you could create this kind of extension. It returns a copy of this list with elements at indices a and b swapped.
fun <T> List<T>.swap(a: Int, b: Int): List<T> = this
.toMutableList()
.also {
it[a] = this[b]
it[b] = this[a]
}
If you use an array, you can use this:
fun <T> Array<T>.swap(i: Int, j: Int) {
with(this[i]) {
this#swap[i] = this#swap[j]
this#swap[j] = this
}
}