random funcional topics

Twofer Exercise in Multiple Languages

2020.09.03

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."
}