What is the preferred usage of conditional statements when you have to alter (or not ) an existing object depending on the conditional

I’m missing a good example of the suggested use of conditional statements in coding conventions document for use cases other than simple assignments or function returns. Suppose you have to return the price of a product and depending of whether or not this product has a discount you need return the price or the price with the applied discounts. Which of the solutions below is the most appropriate and aligned with the official Kotlin coding convention?

Solution 1:

someFunction(...) {
   val price = // we should not be concerned about how we obtain the price
   return if(hasDiscounts(...)) applyDiscounts(price) else price
}

Solution 2:

calculatePrice(...) {
   val price = // we should not be concerned about how we obtain the price
   hasDiscounts(...) {
      return applyDiscounts(price)
  }
  return price
}

Solution 3:

calculatePrice(...) {
   var price = // we should not be concerned about how we obtain the price
   if(hasDiscounts(...) {
      price = applyDiscounts(price)
  }
  return price
}

This is really a matter of taste. My personal opinion is that 3 is definitely the worst. Code is always easier to read if there are mostly immutable values. 1 and 2 are both fine, but I think 1 is better. For similar reason as in var vs val - 2 requires the reader to search for return statements through the code. 1 is very explicit about where the return value is specified.

Also, this is maybe a digression, but as we have the null safety in Kotlin, it is often preferred to not have separate has and get variables/operations, but only get with a nullable value. It opens new possibilities to make conditional code cleaner. If your case would be a little different and we would have hasDiscount() and getDiscountedPrice() functions, then replacing them with just a single function that returns a nullable value would make possible to calculate the final price like this:

return getDiscountedPrice() ?: price

In the case of the applyDiscounts() function it would be a little more weird, but still it is worth considering:

return applyDiscounts?.invoke(price) ?: price