Is it possible to change AlertDialog message only based on condition met? - kotlin

E.g. I have similar code to this post Show AlertDialog if some condition is met
if (condition) {
AlertDialog.Builder(requireActivity())
.setTitle("Internet")
.setMessage("Internet ON")
.setPositiveButton("ok!",null)
.create()
} else {
AlertDialog.Builder(requireActivity())
.setTitle("Internet")
.setMessage("Internet OFF")
.setPositiveButton("ok!",null)
.create()
}
But can I do the check for conditions met inside the message for dialog?
So that I do not rewrite same code twice, but with different message

If you want to use ternary operator like syntax. Kotlin provides kinda the same logic, just a bit different syntax.
Here's an example.
AlertDialog.Builder(requireActivity())
.setTitle("Internet")
.setMessage(if (condition) "Internet ON" else "Internet OFF")
.setPositiveButton("ok!",null)
.create()
Read more here:
https://stackoverflow.com/a/46843369/3010171

Related

Kotlin try statement not working when specifying if without else

Why would this piece of Kotlin code not compile? Needless to say return type is Unit (or void in Java)
The error is: 'if' must have both main and 'else' branches if used as an expression
fun test() =
try {
if (true) {
}
// no else clause
} finally {
print("")
}
It doesn't matter which combination of the try statement I implement (try with catch or try with finally or all of them)
fun test() =
try {
if (true) {
}
// no else clause
} catch (e: Exception) {
print("")
} finally {
print("")
}
Strangely this compiles:
fun test() =
try {
if (true) {
}
print("print something")
} catch (e: Exception) {
print("")
} finally {
print("")
}
Using latest IntelliJ.
try/catch/finally, when, and if/else can be used either as a statement or as an expression. When used as an expression, they have to return something. You are forcing the compiler to treat it as an expression by putting = in front of it.
You return something in try/catch by making it the last thing in your try block and in any catch blocks.
if by itself cannot be an expression. It has to be followed by else to be an expression.
Since the if block is the last thing in your try clause of your try/catch expression, it has to be an expression, because the last thing in the block represents what it returns.
The compiler is complaining because the last thing in your try/catch expression's try block is not an expression. It's an if statement.
When you add println() at the end, that's an expression, so it can be interpreted fine by the compiler. println() evaluates to Unit.
As #Gidds says in the comment below, the whole issue stems from making this a expression in the first place. If you have nothing useful to return (Unit), then make it a statement so you don't have to worry about pleasing the compiler. When you try to make it an expression, the compiler is pedantic because it's trying to prevent you from writing something that doesn't make sense to write if you're trying to return something useful.
Also, if you deliberately express that your expression should evaluate to Unit using : Unit =, then the compiler doesn't enforce that it really has to evaluate as an expression.

Pass no value to function with default parameters

I have this Kotlin function:
fun doSomething(user: User = defaultUser) {
//do something
}
and I call it from another place:
val user: User? = getUser()
if (user == null) {
doSomething()
} else {
doSomething(user)
}
Is it possible to improve this code? I think this "if/else" is a little bit messy. Is possible to do something like this?
doSomething(user ?: NoValue)
You can cut it down to user?.run(::doSomething) ?: doSomething() (if doSomething doesn't return null) but I don't know why you'd want to!
Honestly the if/else reads nice to me, stick it on one line without the braces and it's nice and compact. Unfortunately I don't think you can conditionally add parameters into a function call (and handling default parameters can get unnwieldy when you have a few).
I agree with #benjiii, it might be better to have a nullable parameter and handle the default internally, if you don't need to use null as a legit value
You could do something like this:
getUser()?.let { // user is not null
doSomething(it)
} ?: run { // user is null here
doSomething()
}
(cf: Swift 'if let' statement equivalent in Kotlin)
I don't think you could do something shorter without making the code hard to understand Edit 2: Actually you can, see the comment
Edit: I would personally handle the nullable variable inside the function like this:
fun doSomething(user: User?) {
val correctUser = user ?: defaultUser
//do something
}
so you can use the function like this:
doSomething(getUser())
I agree with cactustictacs, just putting it on one line is clear and simple. However, if you use it often and it's bothering you, it's easy enough to wrap it in a function without the default parameter:
fun doSomethingSensibly(user: User?) =
if (user == null)
doSomething()
else
doSomething(user)
Which can be used as:
doSomethingSensibly(getUser())

Cancelling a coroutine internally?

I need to exit a coroutine in kotlin if a condition is not met. I would like to avoid using nested condition to keep my code clean. This is what I have:
GlobalScope.launch {
var condition: Boolean = false
if (!condition) {
//this does nothing
this.cancel()
}
println("I shouldn't print")
}
You have two ways:
Simply return from your coroutine body with return#launch statement.
Throw an CancellationException just like what this.cancel() does.
And the reason that your code doesn't stop working is because Cancellation is cooperative in coroutines, your code should be cooperate with checking for isActive Or calling yield(), (just like what docs says) to achive such a functionality that you want

Kotlin assignments are not expressions. Any other way to force assertions to be enabled?

I'm currently learning Kotlin, and one way I'm doing it is by automatically converting Java code to Kotlin and studying the results. One piece of Java code I tried to convert is the following static block in a class that tries to ensure that assertions are enabled:
static {
boolean assertsEnabled = false;
assert assertsEnabled = true;
if (!assertsEnabled)
throw new AssertionError("Please enable assertions!");
}
This relies on the assertsEnabled = true expression as an argument to assert. In Java, assignments are expressions. In Kotlin, they're not, and so this can't be converted. Is there any other way to do it?
Unfortunately, Kotlin doesn't have the assert keyword with its special semantics. Instead it has this function:
inline fun assert(value: Boolean, lazyMessage: () -> Any)
You can see that the expression passed as the first argument is evaluated unconditionally. This means you can't achieve the same lightweight check as in Java; you have to trigger an actual assertion failure to make sure.
So you need a check as suggested by #Zoe:
try {
assert(false)
throw IllegalStateException("Please enable assertions!")
} catch (e: AssertionError) {
// Things are looking good; carry on
}
If you insist on throwing an AssertionError instead of IllegalStateException, you can use a boolean variable for that.
var assertionsAreDisabled = false
try {
assert(false)
assertionsAreDisabled = true
} catch (e: AssertionError) {
// Things are looking good; carry on
}
if (assertionsAreDisabled) {
throw AssertionError("Please enable assertions!")
}

Option Chaining instead of if/else

Is there a more succint way to write the following code using option chaining and/or the elvis operator?
email.addSubject(if (creator != null) String.format( inviteDescription, creator) else String.format(inviteDescriptionNoCreator, group))
It feels like there should be.
Using the normal IF expression
val subject = if (creator != null) {
inviteDescription.format(creator)
} else {
inviteDescriptionNoCreator.format(group)
}
email.addSubject(subject)
The Elvis Operator
val subject = creator?.let {
inviteDescription.format(it)
} ?: inviteDescriptionNoCreator.format(group)
email.addSubject(subject)
If the goal is to write the shortest code possible then you could go with a single line Elvis operator. But if the goal is a readable code, I would choose the simple if expression or a multi line Elvis operator. I would even go one step ahead and move it to a separate method. But whatever you choose, please don't write everything in a single long line, rather put it in separate lines.
Just taking advantage of ?. and ?: gives us the following:
email.addSubject(creator?.let { String.format(inviteDescription, it) } ?: String.format(inviteDescriptionNoCreator, group))
Unfortunately, that's still quite long and is arguably not much easier to read. You could shave off a bit more by using the String.format extension function:
email.addSubject(creator?.let { inviteDescription.format(it) } ?: inviteDescriptionNoCreator.format(group))