Why is this an issue?
In Kotlin, if
and when
statements are expressions that return a value. This allows for a more concise and functional
programming style with less cognitive complexity, because it results in fewer return points and fewer variable assignments in a function.
If both branches of an if
statement end with a return
statement, the if
statement should be used instead as
an expression for a return
statement.
If all branches of an exhaustive when
statement end with a return
statement, the when
statement should be
used instead as an expression for a return
statement. A when
statement is exhaustive when it covers all elements of an enum
or features an else
clause.
What is the potential impact?
Readability and Understanding
This change makes it easier to understand a function because it will reduce its complexity. This is because the function now contains fewer return
points that the developer needs to keep track of.
How to fix it
Use the if
statement as an expression for a return
statement. Lift the return
keyword from the end of the
if
band else
branch before the if
keyword.
Use the when
statement as an expression for a return
statement. Lift the return
keyword from the end of all
its case clauses before the when
keyword.
Code examples
Noncompliant code example
fun returnIfElse(value: Int): String {
// ...
if (value >= 0) { // Noncompliant, every branch contains a return statement
return "positive"
} else {
return "negative"
}
}
Compliant solution
fun returnIfElse(value: Int): String {
// ...
return if (value >= 0) { // Compliant
"positive"
} else {
"negative"
}
}
Noncompliant code example
fun returnWhenElse(a: Float): Int {
// ...
when { // Noncompliant, every branch of exhaustive `when` contains a return statement
a < 0 -> return -1
a > 0 -> return 1
else -> return 0
}
}
Compliant solution
fun returnWhenElse(a: Float): Int {
// ...
return when { // Compliant
a < 0 -> -1
a > 0 -> 1
else -> 0
}
}
Noncompliant code example
enum class OneTwoThree {
ONE,
TWO,
THREE
}
fun returnWhenEnum(oneTwoThree: OneTwoThree): String {
// ...
when(oneTwoThree) { // Noncompliant, every branch of exhaustive `when` contains a return statement
OneTwoThree.ONE -> return "one"
OneTwoThree.TWO -> return "two"
OneTwoThree.THREE -> return "three"
}
}
Compliant solution
fun returnWhenEnum(oneTwoThree: OneTwoThree): String {
// ...
return when(oneTwoThree) { // Compliant
OneTwoThree.ONE -> "one"
OneTwoThree.TWO -> "two"
OneTwoThree.THREE -> "three"
}
}
Noncompliant code example
fun returnIfElseWithSideEffects(a: Float, b: Float): Int {
// ...
if (a < 0) { // Noncompliant, every branch contains a return statement
foo()
return -1
} else if (a > b) {
bar()
return 1
} else {
return 0
}
}
Compliant solution
fun returnIfElseWithSideEffects(a: Float, b: Float): Int {
// ...
return if (a < 0) { // Compliant
foo()
-1
} else if (a > b) {
bar()
1
} else {
0
}
}
Resources
Documentation
Articles & blog posts