Traditional high-level programming languages such as Java, C#, and C++ were designed to support imperative/procedural programming. Modern programming languages such as Kotlin make it easier to code more functional and readable solutions. In this post, I start with an imperative, non-Kotlin-esque solution for the FizzBuzz code exercise; I then refine that solution in a series of steps, explaining the following Kotlin features along the way:
val
vsvar
.- String templates.
- Expressions vs statements.
when
expression
FizzBuzz problem
Write a Kotlin function that accepts an integer and returns:
Fizz
for multiples of three.Buzz
for the multiples of five.FizzBuzz
for multiples of three and five.- Returns the number itself for any other integer.
FizzBuzz solution
The Kotlin snippet below is a direct translation of the imperative pre-Java-8 solution here.
fun fizzBuzz(num: Int): String {
var result = ""
if (num % 3 == 0) {
result = "Fizz"
}
if (num % 5 == 0) {
result += "Buzz"
}
if (result == "") {
result = num.toString()
}
return result;
}
So what’s wrong with this solution? Firstly, the variable result
is mutable; we assigned it in several places in the code. The resulting code is hard to read and reason about. Kotlin helps by making the distinction between mutable variables var
and their immutable counterpart val
. Always thrive for immutability, i.e., using val
instead of var
.
But how would you do that? How would you get these if
statement working without assigning result
inside them? The secret is to use if
as expressions instead of statements. Unlike in Java, if
can return a value in Kotlin. Here is the modified code:
fun fizzBuzz(num: Int): String {
return if (num % 3 == 0) "Fizz"
else if (num % 5 == 0) "Buzz"
else if (num % 3 == 0 && num % 5 == 0) "FizzBuzz"
else "$num"
}
The solution above contains an additional improvement: changing num.toString()
to its string template version “$num”. String templates allow you to use placeholders inside strings. It’s a great feature that simplifies string handling significantly, but not a massive improvement in this particular example.
This second version of the code is much better! However, we can improve the readability further by using the when
expression instead of the if-else
chain. If you are familiar with Java, you may find some similarities with Java switch
statement. However, is it way more powerful:
- Can be used as a statement or an expression.
- Branch conditions are more flexible.
- Allows smart casts.
- Generally more readable.
This blog post provides an in-depth explanation of when
expression.
Check here the final version of the code:
fun fizzBuzz(num: Int): String {
return when {
(num % 3 == 0) -> "Fizz"
(num % 5 == 0) -> "Buzz"
(num % 3 == 0 && num % 5 == 0) -> "FizzBuzz"
else -> "$num"
}
}