One of the best sites for practicing functional programming, in my opinion, is Exercism. I thought it would be fun to compare an exercise that is available in multiple languages. The idea here is to show that by programming in a language that is more ‘functional’, it can lead you to think about how you could implement something in a language you don’t normally think of as functional. In general, a functional solution is almost always a better approach.
Here’s the ‘Twofer’ exercise:
Two-fer or 2-fer is short for two for one. One for you and one for me.
Given a name, return a string with the message:
One for X, one for me.
Where X is the given name.
However, if the name is missing, return the string:
One for you, one for me.
Here are some examples:
Name String to return
Alice One for Alice, one for me.
Bob One for Bob, one for me.
<null> One for you, one for me.
Zaphod One for Zaphod, one for me.
I first solved this problem in F# as follows:
// F# solution
module TwoFer
let twoFer (input: string option): string =
input
|> Option.defaultValue "you"
|> sprintf "One for %s, one for me."
When solving the problem in Java, the tendency would be to do somthing like the following, since we tend to think of Java as an imperative language:
// Java initial solution
public class Twofer {
public String twofer(String name) {
if (name == null) {
return "One for you, one for me.";
} else {
return "One for " + name + ", one for me.";
}
}
}
Maybe you’d rather get “fancy” and shorten it a little, like so:
// Java solution with ternary operator
public class Twofer {
public String twofer(String name) {
return String.format("One for %s, one for me.", name == null ? "you" : name);
}
}
However, you can also use the Optional object in Java akin to the F# construct above, and solve the problem the following way, which is my preferred way to do it:
// Java solution with Optional
import java.util.Optional;
public class Twofer {
public String twofer(String name) {
return String.format("One for %s, one for me.", Optional.ofNullable(name).orElse("you"));
}
}
By the way, you can solve the same problem in Kotlin without using an optional construct thanks to support for default arguments:
// Kotlin solution - default arguments
internal fun twofer(name: String = "you"): String {
return "One for $name, one for me."
}