Chapter 16. Interfaces to Functions

In Java, we use interfaces to specify a contract between code that defines some functionality and code that needs it. Those interfaces couple the two parties together, which can make our software harder to maintain. How do function types help solve this problem?

Imagine, if you can, that you need to send email from some code that you are writing. Just that for now—not receive mail, or list sent messages—just fire and forget.

The code that describes the email is simple enough:

data class Email(
    val to: EmailAddress,
    val from: EmailAddress,
    val subject: String,
    val body: String
)

Given an Email, client code would like to call the simplest possible function to send it, which is:

fun send(email: Email) {
    ...
}

Of course when we come to implement this function, we discover that to actually send email, we require all sorts of other information. Not information about the email itself but, rather, configuration about how to send it. Things like the sending server’s hostname and security credentials—all the things that your nontechnical relative doesn’t know, but you need to set up their new computer. We’ll add three extra parameters to sendEmail to stand in for all this configuration:

fun sendEmail(
    email: Email,
    serverAddress: InetAddress,
    username: String,
    password: String
) {
    ...
}

As a client, things have just become a lot less convenient. Everywhere we want to send email has to know this configuration; we’ll be passing it around from the top ...

Get Java to Kotlin now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.