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
Related
Hey I want to use custom comparator in priority queue in kotlin. I have data class
Product.kt
data class Product(val value: String? = null, val price: String? = null) {
var priceInLong = price?.toLong()
}
I want to create a min heap where price value will be minimum. I am creating the object but it giving me some kind of error
fun main() {
var queue = PriorityQueue<Long> { p1: Product, p2: Product ->
p1.priceInLong?.let {
p2.priceInLong?.minus(it)
}
}
val list = listOf(
Product("1", "4.83"),
Product("2", "4.53"),
Product("3", "3.54"),
Product("4", "3.66"),
Product("5", "5.16")
)
}
error
None of the following functions can be called with the arguments supplied.
<init>((MutableCollection<out TypeVariable(E)!>..Collection<TypeVariable(E)!>?)) where E = TypeVariable(E) for constructor PriorityQueue<E : Any!>(c: (MutableCollection<out E!>..Collection<E!>?)) defined in java.util.PriorityQueue
<init>(Comparator<in TypeVariable(E)!>!) where E = TypeVariable(E) for constructor PriorityQueue<E : Any!>(comparator: Comparator<in E!>!) defined in java.util.PriorityQueue
<init>(PriorityQueue<out TypeVariable(E)!>!) where E = TypeVariable(E) for constructor PriorityQueue<E : Any!>(c: PriorityQueue<out E!>!) defined in java.util.PriorityQueue
<init>(SortedSet<out TypeVariable(E)!>!) where E = TypeVariable(E) for constructor PriorityQueue<E : Any!>(c: SortedSet<out E!>!) defined in java.util.PriorityQueue
<init>(Int) where E = TypeVariable(E) for constructor PriorityQueue<E : Any!>(initialCapacity: Int) defined in java.util.PriorityQueue
image
1. I want to solve this error and add value by price which is minimum comes first.
2. Is my above queue comparator logic is correct to use min heap?
Thankss
UPDATE
I tried this suggestion
var queue = PriorityQueue<Product> { p1, p2 ->
return if (p1.priceInLong != null && p2.priceInLong != null) {
p2.priceInLong - p1.priceInLong
} else {
0
}
}
getting error
UPDATE 2
val queue = PriorityQueue<Product> { p1, p2 ->
val priceOne = p1.priceInLong
val priceTwo = p2.priceInLong
if (priceOne != null && priceTwo != null) {
if(priceOne == priceTwo){
return 0
}
} else {
return 0
}
}
data class Product(val value: String? = null, val price: String? = null) {
val priceInLong = price?.toLong()
}
This:
{ p1: Product, p2: Product ->
p1.priceInLong?.let {
p2.priceInLong?.minus(it)
}
}
returns null if p1.priceInLong is null (the let block isn't executed), or if p2.priceInLong is null (the let block returns null). That's what the null-safety checking with ? does.
You're getting the error because your Comparator function needs to return an Int, but yours returns Int?, i.e. a nullable int value - could be an int, could be null. So it doesn't match the required constructor, that's why it's complaining that none of the functions match.
So you need to decide what to do if one (or both) of those values are null, and return an integer instead of any nulls, so your function returns Int and not Int?
If what you're saying in the comments is correct, and neither of those values will ever be null, you can just assert that with !!
{ p1: Product, p2: Product ->
p2.priceInLong!! - p1.priceInLong!!
}
But using !! is a bad sign - how do you know they'll never be null? If you can say that for sure, why is priceInLong nullable in the first place?
I want to solve this error
Two problems here:
Type argument of PriorityQueue should be a Product (if you want to store these objects in it).
Lambda of Comparator should return Int, not Long?. If it's guaranteed, that there will be no Products with priceInLong == null, you may just use the not-null assertion operator to get rid of nullability and then get sign of difference to avoid possible integer overflow of .toInt() conversion:
val queue = PriorityQueue<Product> { p1, p2 -> (p1.priceInLong!! - p2.priceInLong!!).sign }
The following is the kotlin program. I have confusion that why the setter function is not being called on running line x.b=20.
class Num(value: Int) {
var a = value + 4
var b = value + 6
var c = value + 1
set(value) {
println("field is : ${field}")
field = value + b
println("field is : ${field}")
println("inside setter am here")
}
}
fun main(args: Array<String>) {
var x = Num(3)
x.b = 20
println(x.b)
}
It would be much clearer if your indentation were correct:
class Num(value: Int) {
var a = value + 4
var b = value + 6
var c = value + 1
set(value) {
println("field is : ${field}")
field = value + b
println("field is : ${field}")
println("inside setter am here")
}
}
You have only defined a setter on c. There is no way to make one setter for all the values, though factoring out a method might help.
Louis explained why it's not working, but this statement:
There is no way to make one setter for all the values
is not correct. It is possible by using delegated properties:
import kotlin.reflect.KProperty
class Num(value: Int) {
var a by MySetter(value + 4)
var b by MySetter(value + 6)
var c by MySetter(value + 1)
}
class MySetter(private var field) {
operator fun getValue(thisRef: Num, property: KProperty<*>) = field
operator fun setValue(thisRef: Num, property: KProperty<*>, value: Int) {
println("field is : $field")
field += value
println("field is : $field")
println("inside setter am here")
}
}
fun main(args: Array<String>) {
var x = Num(3)
x.b = 20
println(x.b)
}
This prints:
field is : 9
field is : 29
inside setter am here
29
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)
}
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
In Kotlin is there an equivalent to the Swift code below?
if let a = b.val {
} else {
}
You can use the let-function like this:
val a = b?.let {
// If b is not null.
} ?: run {
// If b is null.
}
Note that you need to call the run function only if you need a block of code. You can remove the run-block if you only have a oneliner after the elvis-operator (?:).
Be aware that the run block will be evaluated either if b is null, or if the let-block evaluates to null.
Because of this, you usually want just an if expression.
val a = if (b == null) {
// ...
} else {
// ...
}
In this case, the else-block will only be evaluated if b is not null.
Let's first ensure we understand the semantics of the provided Swift idiom:
if let a = <expr> {
// then-block
}
else {
// else-block
}
It means this: "if the <expr> results in a non-nil optional, enter the then-block with the symbol a bound to the unwrapped value. Otherwise enter the else block.
Especially note that a is bound only within the then-block. In Kotlin you can easily get this by calling
<expr>?.also { a ->
// then-block
}
and you can add an else-block like this:
<expr>?.also { a ->
// then-block
} ?: run {
// else-block
}
This results in the same semantics as the Swift idiom.
My answer is totally a copy cat from the others. However, I cannot understand their expression easily. So I guess it would be nice to provide an more understandable answer.
In swift:
if let a = b.val {
//use "a" as unwrapped
}
else {
}
In Kotlin:
b.val?.let{a ->
//use "a" as unwrapped
} ?: run{
//else case
}
if let statement
Swift if let Optional Binding (so called if-let statement) is used to extract a non-optional value if one exists, or to do nothing if a value is nil.
Swift's if-let statement:
let b: Int? = 50
if let a: Int = b {
print("Good news!")
} else {
print("Equal to 'nil' or not set")
}
/* RESULT: Good news! */
In Kotlin, like in Swift, to avoid crashes caused by trying to access a null value when it’s not expected, a specific syntax (like b.let { } in second example) is provided for properly unwrapping nullable types:
Kotlin's equivalent1 of Swift's if-let statement:
val b: Int? = null
val a = b
if (a != null) {
println("Good news!")
} else {
println("Equal to 'null' or not set")
}
/* RESULT: Equal to 'null' or not set */
Kotlin’s let method, when used in combination with the safe-call operator ?:, provides a concise way to handle nullable expressions.
Kotlin's inline let function and Elvis Operator of Swift's nil coalescing operator:
val b: Int? = null
val a = b.let { nonNullable -> nonNullable } ?: "Equal to 'null' or not set"
println(a)
/* RESULT: Equal to 'null' or not set */
guard let statement
guard-let statement in Swift is simple and powerful. It checks for some condition and if it evaluates to be false, then the else statement executes which normally will exit a method.
Let's explore a Swift's guard-let statement:
let b: Int? = nil
func method() {
guard let a: Int = b else {
print("Equal to 'nil' or not set")
return
}
print("Good news!")
}
method()
/* RESULT: Equal to 'nil' or not set */
Kotlin's similar effect of Swift's guard-let statement:
Unlike Swift, in Kotlin, there is no guard statement at all. However, you can use the Elvis Operator – ?: for getting a similar effect.
val b: Int? = 50
fun method() {
val a = b ?: return println("Equal to 'null' or not set")
return println("Good news!")
}
method()
/* RESULT: Good news! */
there are two answers above, both got a lot acceptances:
str?.let{ } ?: run { }
str?.also{ } ?: run { }
Both seem to work in most of the usages, but #1 would fail in the following test:
#2 seems better.
Unlike Swift, Its not necessary to unwrap the optional before using it in Kotlin. We could just check if the value is non null and the compiler tracks the information about the check you performed and allows to use it as unwrapped.
In Swift:
if let a = b.val {
//use "a" as unwrapped
} else {
}
In Kotlin:
if b.val != null {
//use "b.val" as unwrapped
} else {
}
Refer Documentation: (null-safety) for more such use cases
Here's how to only execute code when name is not null:
var name: String? = null
name?.let { nameUnwrapp ->
println(nameUnwrapp) // not printed because name was null
}
name = "Alex"
name?.let { nameUnwrapp ->
println(nameUnwrapp) // printed "Alex"
}
Here's my variant, limited to the very common "if not null" case.
First of all, define this somewhere:
inline fun <T> ifNotNull(obj: T?, block: (T) -> Unit) {
if (obj != null) {
block(obj)
}
}
It should probably be internal, to avoid conflicts.
Now, convert this Swift code:
if let item = obj.item {
doSomething(item)
}
To this Kotlin code:
ifNotNull(obj.item) { item ->
doSomething(item)
}
Note that as always with blocks in Kotlin, you can drop the argument and use it:
ifNotNull(obj.item) {
doSomething(it)
}
But if the block is more than 1-2 lines, it's probably best to be explicit.
This is as similar to Swift as I could find.
There is a similar way in kotlin to achieve Swift's style if-let
if (val a = b) {
a.doFirst()
a.doSecond()
}
You can also assigned multiple nullable values
if (val name = nullableName, val age = nullableAge) {
doSomething(name, age)
}
This kind of approach will be more suitable if the nullable values is used for more than 1 times. In my opinion, it helps from the performance aspect because the nullable value will be checked only once.
source: Kotlin Discussion
I'm adding this answer to clarify the accepted answer because it's too big for a comment.
The general pattern here is that you can use any combination of the Scope Functions available in Kotlin separated by the Elvis Operator like this:
<nullable>?.<scope function> {
// code if not null
} :? <scope function> {
// code if null
}
For example:
val gradedStudent = student?.apply {
grade = newGrade
} :? with(newGrade) {
Student().apply { grade = newGrade }
}
The cleanest option in my opinion is this
Swift:
if let a = b.val {
} else {
}
Kotlin
b.val.also { a ->
} ?: run {
}
Swift if let statement in Kotlin
The short answer is use simple IF-ELSE as by the time of this comment there is no equivalent in Kotlin LET,
if(A.isNull()){
// A is null
}else{
// A is not null
}
we can get the same Unwraping syntax like Swift if let using inline fun
inline fun <T:Any?> T?.unwrap(callback: (T)-> Unit) : Boolean {
return if (this != null) {
this?.let(callback)
true
}else {
false
}
}
Uses: :
val name : String? = null
val rollNo : String? = ""
var namesList: ArrayList<String>? = null
if (name.unwrap { name ->
Log.i("Dhiru", "Name have value on it $name")
})else if ( rollNo.unwrap {
Log.i("Dhiru","Roll have value on it")
}) else if (namesList.unwrap { namesList ->
Log.i("Dhiru","This is Called when names list have value ")
}) {
Log.i("Dhiru","No Field have value on it ")
}
The problem with the Any?.let {} ?: run {} constructions is that:
It only allows for one non-null check per statement
If the let block returns null the run block is evaluated anyway
It's not possible to perform multiple checks in a switch/when style
A solution which tackles most of these problems is to define functions like the following:
private inline fun <A> ifNotNull(p1: A?, block: (A) -> Unit): Unit? {
if (p1 != null) {
return block.invoke(p1)
}
return null
}
private inline fun <A, B> ifNotNull(p1: A?, p2: B?, block: (A, B) -> Unit): Unit? {
if (p1 != null && p2 != null) {
return block.invoke(p1, p2)
}
return null
}
private inline fun <A, B, C> ifNotNull(p1: A?, p2: B?, p3: C?, block: (A, B, C) -> Unit): Unit? {
if (p1 != null && p2 != null && p3 != null) {
return block.invoke(p1, p2, p3)
}
return null
}
This would allow for a statement like:
ifNotNull(a, b) { a, b ->
// code when a, b are not null
} ?:
ifNotNull(c) { c ->
// code when a, b are null and c not null
} ?:
ifNotNull(d, e, f) { d, e, f ->
// code when a, b, c are null and d, e, f not null
} ?: run {
// code which should be performed if a, b, c, d, e and f are null
}
The only caveat is that continue and break statements are not supported if executed within a loop compared to Swift's if let equivalent.
Probably I am very late however the easiest way to unwrap and option is
yourOptionalString ?: return
this was all the following lines will have unwrapped string
If b is a member variable then this approach seems most readable to me:
val b = this.b
if (b == null) {
return
}
println("non nullable : ${b}")
This is also consistent with how it works in swift, where a new local variable shadows the member variable.