arrow ensure doesn't make value non nullable after check - kotlin

have a question about ensure function, somehow it doesn't make null safe after check in either block.
What I am doing wrong, or is there a better way to ensure that value is not null except of using !!
here is my code
suspend fun checkCanConnectDirectChat(
senderId: Int?,
receiverId: Int?,
chatRoomId: Int?
) = either {
ensure(chatRoomId != null && receiverId != null) {
BadRequestExceptionResponse(message = ErrorConstants.INVALID_PAYLOAD)
}
val isSenderInChat = isUserInChat(chatRoomId, senderId).bind()
val isReceiverInChat = isUserInChat(chatRoomId, receiverId).bind()
ensure(isSenderInChat && isReceiverInChat){
BadRequestExceptionResponse(message = ErrorConstants.INVALID_PAYLOAD)
}
}
after the ensure I still see that they are nullable

Unfortunately the compiler is not "clever enough" to know that if the check inside ensure talks about null-ness, then within the block that holds. The best solution is to use the *NotNull family of functions, some of them available at Arrow, some of them available in the standard library.

In this case you would use ensureNotNull, which smart-casts the value to be not nullable.
suspend fun checkCanConnectDirectChat(
senderId: Int?,
receiverId: Int?,
chatRoomId: Int?
) = either {
ensureNotNull(chatRoomId) {
BadRequestExceptionResponse(message = ErrorConstants.INVALID_PAYLOAD)
}
ensureNotNull(receiverId) {
BadRequestExceptionResponse(message = ErrorConstants.INVALID_PAYLOAD)
}
val isSenderInChat = isUserInChat(chatRoomId, senderId).bind()
val isReceiverInChat = isUserInChat(chatRoomId, receiverId).bind()
ensure(isSenderInChat && isReceiverInChat){
BadRequestExceptionResponse(message = ErrorConstants.INVALID_PAYLOAD)
}
}

Related

Is there a simple code for fun addDetail in Kotlin?

The following code can work well, but the code of fun addDetail(...) is too complex, is there a simple way to do that ? Thanks!
BTW, in the fun addDetail(...), aMListDetail maybe null, and aMListDetail?.innerListDetail maybe null.
data class MDetail (
val _id: Long
)
class DetailsHandler(mContext: Context = UIApp.instance) {
data class MListDetail(val innerListDetail: MutableList<MDetail>)
private var aMListDetail: MListDetail?
var mJson: String by PreferenceTool(mContext,"mySavedJson", "")
init {
aMListDetail= Gson().fromJson(mJson,MListDetail::class.java)
}
fun addDetail(aMDetail:MDetail){
if (aMListDetail==null){
aMListDetail=MListDetail(mutableListOf(aMDetail))
}else{
if (aMListDetail?.innerListDetail==null){
aMListDetail=MListDetail(mutableListOf(aMDetail))
}else {
aMListDetail?.innerListDetail?.add(aMDetail)
}
}
mJson = Gson().toJson(aMListDetail)
}
}
fun addDetail(aMDetail: MDetail) {
if (aMListDetail?.innerListDetail == null) {
aMListDetail = MListDetail(mutableListOf(aMDetail))
} else {
aMListDetail.innerListDetail.add(aMDetail)
}
mJson = Gson().toJson(aMListDetail)
}
Alternative:
fun addDetail(aMDetail: MDetail) {
if (aMListDetail?.innerListDetail == null) {
aMListDetail = MListDetail(mutableListOf())
}
aMListDetail.innerListDetail.add(aMDetail)
mJson = Gson().toJson(aMListDetail)
}
You don't need null-safe ?. operators in your add() call, since at that point you've already checked that aMListDetail != null and innerListDetail != null.
BTW, in the fun addDetail(...), aMListDetail maybe null,
Why not fix the problem at the source? You initialize it in the constructor, then tell Kotlin it could be set to null, but actually you never do this!
If you remove the unused nullability, the code simplifies to:
class DetailsHandler(mContext: Context = UIApp.instance) {
data class MListDetail(val innerListDetail: MutableList<MDetail>)
var mJson: String by PreferenceTool(mContext,"mySavedJson", "")
// can even be val
private var aMListDetail: MListDetail
init {
aMListDetail= Gson().fromJson(mJson,MListDetail::class.java)
}
fun addDetail(aMDetail:MDetail){
aMListDetail.innerListDetail.add(aMDetail)
mJson = Gson().toJson(aMListDetail)
}
}
If your real code doesn't initialize it at the beginning, consider by lazy or by notNull.
and aMListDetail?.innerListDetail maybe null.
Only is aMListDetail is null, which you should avoid as above.
Finally, if you really need aMListDetail to be null sometimes, you can write
aMListDetail?.let {
it.innerListDetail.add(aMDetail)
}
(which does nothing if aMListDetail is null)
fun addDetail(aMDetail:MDetail){
if (aMListDetail?.innerListDetail==null){
aMListDetail=MListDetail(mutableListOf(aMDetail))
}else {
aMListDetail?.innerListDetail?.add(aMDetail)
}
mJson = Gson().toJson(aMListDetail)
}
8-)

Swift 'if let' statement equivalent in Kotlin

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.

Check for null in map function in Kotlin

I'm new to Kotlin and I want to map an object (ProductVisibility) base on another one (fmpProduct). Some object can't be converted so I need to skip them on some condition.
I wanted to know if there's a better way to do this than what I did with the filter and the "!!" I feel that it's hacked. Am I missing something ?
val newCSProductVisibility = fmpProducts
.filter { parentIdGroupedByCode.containsKey(it.id) }
.filter { ProductType.fromCode(it.type) != null } //voir si on accumule les erreus dans une variable à montrer
.map {
val type = ProductType.fromCode(it.type)!! //Null already filtered
val userGroupIds = type.productAvailabilityUserGroup.map { it.id }.joinToString(",")
val b2bGroupIds = type.b2bUserGroup.map { it.id }.joinToString { "," }
val b2bDescHide = !type.b2bUserGroup.isEmpty()
val parentId = parentIdGroupedByCode[it.id]!! //Null already filtered
CSProductDao.ProductVisibility(parentId, userGroupIds, b2bGroupIds, b2bDescHide)
}
edit: updated the map access like comment suggested
Use mapNotNull() to avoid the filter()s and do everything in the mapNotNull() block, then the automatic typecast to non-null type works.
Example:
fun f() {
val list = listOf<MyClass>()
val v = list.mapNotNull {
if (it.type == null) return#mapNotNull null
val type = productTypeFromCode(it.type)
if (type == null) return#mapNotNull null
else MyClass2(type) // type is automatically casted to type!! here
}
}
fun productTypeFromCode(code: String): String? {
return null
}
class MyClass(val type: String?, val id: String)
class MyClass2(val type: String)

Best way to handle such scenario where "smart cast is imposible"

I wonder what is the best way to handle such scenario
class Person(var name:String? = null, var age:Int? = null){
fun test(){
if(name != null && age != null)
doSth(name, age) //smart cast imposible
}
fun doSth (someValue:String, someValue2:Int){
}
}
What is the simplest way to call doSth method and making sure that name and age are nt null?
I am looking for something simple as with one variable scenario where I would simply use let
name?.let{ doSth(it) }
You can nest let as much as you like so:
fun test(){
name?.let { name ->
age?.let { age ->
doSth(name, age) //smart cast imposible
}
}
}
Another approach, that might be easier to follow, is to use local variables:
fun test(){
val name = name
val age = age
if(name != null && age != null){
doSth(name, age)
}
}
Last but not least, consider changing Person to be immutable like so:
data class Person(val name:String? = null, val age:Int? = null){
fun test(){
if(name != null && age != null){
doSth(name, age)
}
}
...
}
For the cast to be possible you have to make a local copy of the value somehow. In Kotlin this is best done explicitly:
val name = name
val age = age
if(name != null && age != null){
doSth(name, age)
}
The let function hides this behind an abstraction layer, which is not the best IMHO.
There's a nice, little lib that allows for writing let-like code with multiple variables. It's open-source and you can find it on GitHub, it's called Unwrap
Example based on readme:
unwrap(_a, _b, _c) { a, b, c ->
println("$a, $b$c") // all variables are not-null
}
All unwrap(...) methods are marked inline so there should be no overhead with using them.
By the way, this lib also allows to handle situation when there are some null variables (the nah() method).
If you want to take it a little "extreme" you could define an extension function on Pair<String?,Int?> that hides the logic for you:
fun Pair<String?,Int?>.test(block: (String, Int) -> Unit) {
if(first != null && second != null) {
block(first, second)
}
}
then, calling it will be a little more concise
(name to age).test { n, a ->
println("name: $n age: $a")
}
However, it won't really help you (since you could as well define this as a function inside the Person class itself), unless you need this kind of functionality really often throughout the whole project. Like I said, it seems overkill.
edit
you could actually make it (a little) more useful, by going fully generic:
fun <T,R> Pair<T?,R?>.ifBothNotNull(block: (T, R) -> Unit) {
if(first != null && second != null){
block(first, second)
}
}
In addition to miensol's answer there are various ways to copy property values into function variables to enable smart cast. e.g.:
Intermediary function:
class Person(var name: String? = null, var age: Int? = null) {
fun test() = test(name, age)
private fun test(name: String?, age: Int?) {
if (name != null && age != null)
doSth(name, age) //smart cast possible
}
fun doSth(someValue: String, someValue2: Int) {
}
}
Anonymous function:
class Person(var name: String? = null, var age: Int? = null) {
fun test() = (fun(name: String?, age: Int?) {
if (name != null && age != null)
doSth(name, age) //smart cast possible
})(name, age)
fun doSth(someValue: String, someValue2: Int) {
}
}
Default arguments:
class Person(var name: String? = null, var age: Int? = null) {
fun test(name: String? = this.name, age: Int? = this.age) {
if (name != null && age != null)
doSth(name, age) //smart cast possible
}
fun doSth(someValue: String, someValue2: Int) {
}
}
It is possible to define an inline method that allows you to take N parameters in order to avoid nesting lets (I'm basing my answer on this).
inline fun <T1: Any, T2: Any, R: Any> safeLet(p1: T1?, p2: T2?, block: (T1, T2)->R?): R? {
return if (p1 != null && p2 != null) block(p1, p2) else null
}
Then
fun test() {
safeLet(name, age, {name, age ->
doSth(name, age) //smart cast
});
}
I was having the problem while assigning text to textview with same problem description.
All I did was putting double exclamation mark after the name of my textview.
For example:
var name:TextView?=null
name = findViewById(R.id.id_name)
name!!.text = "Your text"

Best way to null check in Kotlin?

Should I use double =, or triple =?
if(a === null) {
//do something
}
or
if(a == null) {
//do something
}
Similarly for 'not equals':
if(a !== null) {
//do something
}
or
if(a != null) {
//do something
}
A structural equality a == b is translated to
a?.equals(b) ?: (b === null)
Therefore when comparing to null, the structural equality a == null is translated to a referential equality a === null.
According to the docs, there is no point in optimizing your code, so you can use a == null and a != null
Note that if the variable is a mutable property, you won't be able to smart cast it to its non-nullable type inside the if statement (because the value might have been modified by another thread) and you'd have to use the safe call operator with let instead.
Safe call operator ?.
a?.let {
// not null do something
println(it)
println("not null")
}
You can use it in combination with the Elvis operator.
Elvis operator ?: (I'm guessing because the interrogation mark looks like Elvis' hair)
a ?: println("null")
And if you want to run a block of code
a ?: run {
println("null")
println("The King has left the building")
}
Combining the two
a?.let {
println("not null")
println("Wop-bop-a-loom-a-boom-bam-boom")
} ?: run {
println("null")
println("When things go null, don't go with them")
}
Kotlin ways of handling null
Secure Access Operation
val dialog : Dialog? = Dialog()
dialog?.dismiss() // if the dialog will be null,the dismiss call will be omitted
Let function
user?.let {
//Work with non-null user
handleNonNullUser(user)
}
Early exit
fun handleUser(user : User?) {
user ?: return //exit the function if user is null
//Now the compiler knows user is non-null
}
Immutable shadows
var user : User? = null
fun handleUser() {
val user = user ?: return //Return if null, otherwise create immutable shadow
//Work with a local, non-null variable named user
}
Default value
fun getUserName(): String {
//If our nullable reference is not null, use it, otherwise use non-null value
return userName ?: "Anonymous"
}
Use val instead of var
val is read-only, var is mutable. It’s recommended to use as many read-only properties as you can, they are thread-safe.
Use lateinit
Sometimes you can’t use immutable properties. For example, it happens on Android when some property is initialized in onCreate() call. For these situations, Kotlin has a language feature called lateinit.
private lateinit var mAdapter: RecyclerAdapter<Transaction>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAdapter = RecyclerAdapter(R.layout.item_transaction)
}
fun updateTransactions() {
mAdapter.notifyDataSetChanged()
}
Both approaches generate the same bytecode so you can choose whatever you prefer.
Addition to #Benito Bertoli,
the combination is actually unlike if-else
"test" ?. let {
println ( "1. it=$it" )
} ?: let {
println ( "2. it is null!" )
}
The result is:
1. it=test
But if:
"test" ?. let {
println ( "1. it=$it" )
null // finally returns null
} ?: let {
println ( "2. it is null!" )
}
The result is:
1. it=test
2. it is null!
Also, if use elvis first:
null ?: let {
println ( "1. it is null!" )
} ?. let {
println ( "2. it=$it" )
}
The result is:
1. it is null!
2. it=kotlin.Unit
Check useful methods out, it could be useful:
/**
* Performs [R] when [T] is not null. Block [R] will have context of [T]
*/
inline fun <T : Any, R> ifNotNull(input: T?, callback: (T) -> R): R? {
return input?.let(callback)
}
/**
* Checking if [T] is not `null` and if its function completes or satisfies to some condition.
*/
inline fun <T: Any> T?.isNotNullAndSatisfies(check: T.() -> Boolean?): Boolean{
return ifNotNull(this) { it.run(check) } ?: false
}
Below is possible example how to use those functions:
var s: String? = null
// ...
if (s.isNotNullAndSatisfies{ isEmpty() }{
// do something
}
I want to respond to answers of #Benito Bertoli and #BingLi224 and provide imho correct solution.
Problem is with using let, because result of let is it's last expression. You just want to pass the same thing as is passed into it, so also is a better solution. At the same time, after using elvis operator, let is impossible to use, because there is no object to call extension function to so I am using run (functional version). More on that in the scope functions official documentation
Another downside of this compared to using if/when is not being able to use this as an expression so I wouldn't recommend using it :-)
Final code:
"test"?.also {
println("1. it=$it")
} ?: run {
println("2. it is null!")
}
"test"?.also {
println("1. it=$it")
null
} ?: run {
println("2. it is null!")
}
null?.also {
println("1. it is null!")
} ?: run {
println("2. it is null")
}
null?.also {
println("1. it is null!")
null
} ?: run {
println("2. it is null")
}
And output:
1. it=test
1. it=test
2. it is null
2. it is null