how can I delete When statement on this code (Kotlin) - kotlin

val customerInfo = when {
visitor.isCustomer -> customerService.getCustomerInfo(visitorId )
else -> null
}
In this Code, visitor.isCustomer is Boolean ( true / false)
Now then, I don't like specify else -> null into the code.
so i want to delete when statement and convert other ways..
How can I do that?
(I prefer to convert it with StandardKt (like let, apply, also... ))

You can just use an if/else
val customerInfo = if (visitor.isCustomer) customerService.getCustomerInfo(visitorId) else null

You could do something like
val customerInfo = vistorId.takeIf { visitor.isCustomer }?.let { customerService.getCustomerInfo(it) }
But I think a when or if statement is cleaner and more readable.
I think JetBrains coding convention would recommend an if statement instead of a when statement here.

Hope this will be more readable.
Without any additional things,
val customerInfo = if (visitor.isCustomer) customerService.getCustomerInfo(visitorId) else null
With your own extension functions
2)Without infix: (condition).ifTrueElseNull{ return value}
inline fun <T> Boolean?.ifTrueElseNull(block: () -> T): T? {
if (this == true) {
return block()
}
return null
}
var a = visitor.isCustomer.ifTrueElseNull{customerService.getCustomerInfo(visitorId)}
With infix: (condition) ifTrueElseNull{ return value}
inline infix fun <T> Boolean?.ifTrueElseNull(block: () -> T): T? {
if (this == true) {
return block()
}
return null
}
var a = visitor.isCustomer ifTrueElseNull{customerService.getCustomerInfo(visitorId)}

Related

Kotlin ? vs ?.let {}

Consider this nice utility extension function i wanted to use :
inline infix fun <T> T?.otherwise(other: () -> Unit): T? {
if (this != null) return this
other()
return null
}
It could be very useful for logging stuff when expressions evaluated to null for example:
val x: Any? = null
x?.let { doSomeStuff() } otherwise {Log.d(TAG,"Otherwise happened")}
but I see that it wont work for :
val x: Any? = null
x?.otherwise {Log.d(TAG,"Otherwise happened")}
see here for running example
Well when thinking about it i guess that makes sense that if x is null the ? makes the postfix not be executed, but i dont understand why the let in the first example is any different?
Is it possible to fix the utility to be more robust and work without having to have let in the chain?
First, you can simplify the implementation:
inline infix fun <T> T?.otherwise(other: () -> Unit): T? {
if (this == null) { other() }
return this
}
Or
inline infix fun <T> T?.otherwise(other: () -> Unit): T? =
also { if (it == null) other() }
When you do this:
null?.otherwise { println("Otherwise happened") }
?. means "execute if not null", so otherwise is not executed.
What you need to write is:
null otherwise { println("Otherwise happened") }
Note this is very similar to the ?: operator (as Vadik pointed out in the comments):
null ?: println("Otherwise happened")
The difference is that otherwise always returns the value on the left (the same as also), but ?: returns the value on the right when the value on the left is null.
In my opinion, otherwise is confusing, especially as it always returns the left value despite the name. You would be better to use the ?: operator. Or perhaps rename it to something like alsoIfNull.
The let example executes because, when you don't utilize the infix feature, it looks like this:
x?.let {}.otherwise {println("1")}
Notice that it's not ?.otherwise; therefore, it always executes.
So to use otherwise without let, you can omit the ?.
x.otherwise { ... }
x?.let { doSomeStuff() }.otherwise {Log.d(TAG,"Otherwise happened")}
// ⬇️
val value = if (x != null) {
doSomeStuff()
} else {
null
}
value.otherwise {Log.d(TAG,"Otherwise happened")}
x?.otherwise { Log.d(TAG,"Otherwise happened") }
// ⬇️
if (x != null) {
otherwise { Log.d(TAG,"Otherwise happened") }
} else {
null
}
?. means if the value is not null then execute the method and return the result otherwise return null

What is the elegant way of for loop with condition to add to a list in Kotlin

What is the more elegant way of doing the following code in Kotlin
fun bar(bars:List<Bar>): List<Foo>{
val foos = mutableListOf<Foo>()
for(bar in bars){
val foo = foo(bar)
if(foo != null){
foos.add(foo)
}
}
return foos
}
fun foo(bar:Bar): Foo?{
if(bar.something){
return null
}
return Foo()
}
bar() can be rewritten to use mapNotNull():
fun bar(bars: List<Bar>) = bars.mapNotNull{ foo(it) }
or (using a method reference):
fun bar(bars: List<Bar>) = bars.mapNotNull(::foo)
And foo() could also be written with an expression body:
fun foo(bar: Bar) = if (bar.something) null else Foo()
(I've omitted the return types too, as the compiler easily infers them — though you may want to keep them for extra safety/readability.)
Both would also work well as extension functions:
fun List<Bar>.bar() = mapNotNull{ it.foo() }
fun Bar.foo() = if (something) null else Foo()
The whole thing can be simplified to:
bars.filterNot { it.something }.map { Foo() }
This is because you are doing two things:
foo returns Foo() if a certain property is false, otherwise returns null
bar filters out the non-null results.
So what you want are Foo objects for every bar where Bar.something is false, which is what this does.
Working example:
class Foo
data class Bar(val something: Boolean)
fun List<Bar>.toFoos(): List<Foo> = filterNot { it.something }.map { Foo() }
fun main() {
val input = listOf(Bar(true), Bar(false), Bar(false), Bar(true), Bar(true))
val output = input.toFoos()
println(output)
}
Output;
[Foo#4a574795, Foo#f6f4d33]
U could use mapNotNull().
val foos = bars.mapNotNull { foo(it) }
Hope its elegant enough.
These two functions could be replaced with the following one-liner:
fun bar(bars:List<Bar>): List<Foo> = Array(bars.count { !it.something }) { Foo() }.asList()
the elegent way is to write it in a functional way :
fun bar(bars: List<Bar>): List<Foo> {
return bars.filter { !it.something }.map { Foo() }
}

Boolean expression with nullable variables

I am tinkering around with Kotlin and I am trying to wrap my head around how nullable variables work in Kotlin. Here I have a piece of code that does a boolean check to see if a vehicle is over capacity. Is the implementation a good way to work with nullable variables or is there a more elegant way ?
class Route(var vehicle: Vehicle?, var jobs: List<Job>?) {
constructor()
constructor(vehicle: Vehicle?)
fun isOverCapacity() : Boolean {
val vehicleCapacity = vehicle?.capacity
if (vehicleCapacity != null){
val totalDemand = jobs?.sumBy { job -> job.demand }
if (totalDemand != null) {
return totalDemand > vehicleCapacity
}
}
return false
}
}
Thanks a lot!
fun isOverCapacity(): Boolean {
val vehicleCapacity = vehicle?.capacity ?: return false
val totalDemand = jobs?.sumBy { job -> job.demand } ?: return false
return totalDemand > vehicleCapacity
}
What does ?: do in Kotlin? (Elvis Operator)
By using kotlin std-lib dsl functional operators like let, run, also, apply, use.
Use of ?. -> if the object/value is not null then only call the next function.
let -> returns the result of lambda expression.
run -> returns the result of lambda expression passing this as receiver.
also -> does operation and returns itself unlike the result of lambda.
apply -> does operation and returns itself unlike the result of lambda passing this as receiver.
use -> returns the result of lambda expression and closes the Closeable resource.
You can simplify the code as follows:
fun isOverCapacity() : Boolean =
vehicle?.capacity?.let { vehicleCapacity ->
jobs?.sumBy { job -> job.demand }?.let { totalDemand ->
totalDemand > vehicleCapacity
}
} ?: false

Is there a way to distinguish between a function argument's default value having been passed explicitly or implicitly in Kotlin?

Assuming a kotlin function like this:
fun f(p1: T1? = null, p2: T2? = null, ..., pN: TN? = null) {
// ...
}
Can the above function's implementation distinguish between the following two calls, where the first one passed p1 = null implicitly, and the second one passed it explicitly?
f() // Implicit
f(null) // Explicit
f(p1 = null) // Explicit
Note: There could be arbitrary numbers of parameters
No, it cannot distinguish between those cases.
You could distinguish between them if you added a distinct overload, however.
Although I'd rather not use that approach in production, you could do something like I've done in the following snippet:
object Default {
val defaultMapping = mutableMapOf<KClass<*>, Any?>()
inline fun <reified T> get(): T? =
T::class.let {
defaultMapping[it] ?: it.java.constructors.getOrNull(0)?.let { c ->
try {
// NOTE: for now only parameterles constructor will work
c.newInstance()
} catch (e: Exception) {
e.printStackTrace()
null
}.also { v ->
defaultMapping[it] = v
}
} ?: run {
defaultMapping[it] = null
null
}
} as? T
inline fun <reified T> T.isDefault(): Boolean = defaultMapping[T::class] == this
}
inline fun <reified T> foo(bar: T? = Default.get()) {
if (bar?.isDefault() == true) println("bar: default is in use")
else println("bar: $bar")
}
fun main() {
foo<Any>()
foo(Default.get<Any>())
foo<Any>(null)
foo<Any>(bar = null)
foo(Any())
val a = Any()
foo(a)
foo(bar = a)
}
Note, that I have not polished the code in any way. Some parts are leftovers from several attempts (e.g. the part about the constructors.getOrNull(0)) and I don't intend to improve that.
Also: This simple approach only works with default constructors (see it.newInstance()) on the JVM. So that's no multi-platform solution in any way.
The result is something like
bar: default is in use
bar: default is in use
bar: null
bar: null
bar: java.lang.Object#41906a77
bar: java.lang.Object#4b9af9a9
bar: java.lang.Object#4b9af9a9
Again: Keep in mind, this is very simplistic, don't use that in production!

How would I write this in idiomatic Kotlin?

I have some code:
private fun getTouchX(): Int {
arguments ?: return centerX()
return if (arguments.containsKey(KEY_DOWN_X)) {
arguments.getInt(KEY_DOWN_X)
} else {
centerX()
}
}
private fun centerX() = (views.rootView?.width ?: 0) / 2
and I want to shorten it.
in the function getTouchX, there are two return conditions duplicated. (which is centerX)
I tried to do this:
private fun getTouchX(): Int {
if (arguments == null || !arguments.containsKey(KEY_DOWN_X)) {
return centerX()
}
return arguments.getInt(KEY_DOWN_X)
}
However, it looks more like Java than Kotlin.
How could I go about writing this in idiomatic Kotlin?
I'm not sure where arguments is coming from, but a cleaner solution would be
private fun getTouchX(): Int =
if(arguments?.containsKey(KEY_DOWN_X) == true) {
arguments.getInt(KEY_DOWN_X)
} else {
centerX()
}
The if only calls containsKey if arguments is non-null, otherwise the left side of == resolves to null. null != true, so it will return centerX() from else.
Similarly if arguments is non-null, then the result of containsKey will be used to resolve.
And now that there's only one expression, can use body expression format.
I'd probably go with an expression function with a when expression:
private fun getTouchX() = when {
arguments == null || !arguments.containsKey(KEY_DOWN_X) -> centerX()
else -> arguments.getInt(KEY_DOWN_X)
}
You could also consider declaring touchX as a private val:
private val touchX: Int
get() = when {
arguments == null || !arguments.containsKey(KEY_DOWN_X) -> centerX()
else -> arguments.getInt(KEY_DOWN_X)
}
Looking at just the plain Kotlin code, my suggestion would be:
private fun getTouchX() =
arguments?.let {
if (!it.containsKey(KEY_DOWN_X))
return#let null
it.getInt(KEY_DOWN_X)
} ?: centerX()
But if arguments is a descendent of an Android BaseBundle, you might further compress this to:
private fun getTouchX() = arguments?.getInt(KEY_DOWN_X, centerX()) ?: centerX()
Note: As the method signature suspiciously looks like reading a property, you might consider turning it into a read-only property.