Function Divertimento

This Kotlin idiom is not a discovery of mine, but I do not recall the source for it. If you have any references to it, please let me know.
Function signatures⌗
In Kotlin, types can describe the inputs and outputs of functions, e.g.
typealias Predicate = () -> Bool // Takes no argument, returns a bool
typealias VoidFn = () -> Unit // Takes no arguments, returns Unit
So it is possible to define variables that are just functions:
val isTrue: Predicate = { false }
val result = isTrue()
… which can be called.
It is also possible to pass functions as arguments:
fun apply(val a: Int, val func: (Int) -> Int): Int = func(a)
fun add1(val a: Int) = a + 1
apply(3, ::add1) // returns 2
For various reasons, the syntax gets variegated. Let’s look at the example above in an equivalent form:
val add1 = { a: Int -> a + 1 } // add1 is still (Int) -> Int
apply(3, add1) // yep, 2
You can see the :: syntax is to refer to functions in the current namespace.
Now, naming the variable inside the closure is fine and dandy, sometimes, for clarity, but Kotlin lets you elide it,
and will create a “fake” variable called it for you, for as long as the compiler can infer its type:
val add1: (Int) -> Int = { it + 1 }
And before you start moaning about how Java makes you type the same long type names again and again, remember that Java fought in World War II, and Kotlin has never seen a DVD, nor a landline. Type inference at the time probably required more computer power available than the total installed worldwide, which was probably around 2 centiflops.
What happens if we inline add1 above?
apply(3, { it + 1 }) // still 2
The Kotlin language team did us a solid, and proclaimed something like “When the last argument of a function is a closure”, ’tis OK to put the braces outside’, which gives us this awesome syntax:
apply(3) {
it + 1
}
This should cast some light onto which(), also(), filter(), etc. and their apparent wizardry: it
is just a function parameter.
First class functions⌗
It’s not the champagne and extra legroom; what makes functions first class1 is that they can be used anywhere any other variable can be used… passed as a parameter, or returned by a function:
fun multiplierBy(val i: Int): (Int) -> Int = { j -> i * j }
val doubler = multiplierBy(2) // doubler: (int) -> Int
There’s a bit of a corner case here, in terms of function signatures, which is that whole extension function receiver thing. I’ll just show an example of what a type looks like with an extension function:
fun String.combobulate(): String // type is String.() -> String
It is nice that the type signature mirrors the syntax of extension functions. Extensions are incredible in several respects, and super useful in, for instance, creating domain specific languages in Kotlin, which definitely warrants a post or two in the future.
Now, for some reason, ever since the time of Alonzo Church, function signatures have gotten computer scientists extremely excited, them having since devised crazy ways of putting functions together, for instance turning a function of several arguments into several functions of one argument
Another one of those is called partial execution, which is kinda like parbaking, except for functions instead of baguettes. The idea is to take a function that takes, say, two arguments and turn it into a function that takes one argument, in a way that preserves the original. Let me describe it in code, which should be clearer:
fun add(a: Int, b: Int): Int
fun partializer(a: Int, f: (Int, Int) -> Int): (Int) -> Int
val partial = partializer(3, ::add)
partial(2) // returns 5
Calling partializer(3) appears to bake in a=3 into add(). In fact, it is possible to inline partial,
which looks like this:
partializer(3, ::add)(2) // still 5
Note that the signature of partializer is (Int, (Int, Int) -> Int) -> (Int) -> Int: “A function with parameters:
and Int
and a function that takes to Ints. This function returns a function that takes an Int and returns an Int.”
Let’s take a look at partializer():
fun partializer(a: Int, f: (Int, Int) -> Int) = { b -> f(a, b) }
Type inference spares us from having to specify the type of partializer(), thank goodness.
Partial-ish functions through inheritance.⌗
This style of functional code (that is, code that just uses functions instead of classes and objects) is clean and elegant, but fails to acknowledge the reality of why OOP came about, and why singletons and factories were all the rage: real software takes place within a tremendous amount of context, both due to execution constraints and cross-cutting concerns, such as the current logged in user, current request, application configuration, logging, tracing, code instrumentation, etc. OOP sought to capture execution context behind encapsulation, and cross-cutting concerns behind factories.
Functional or imperative code can only access those concerns through function parameters or global state. The reality is that what we concern ourselves with as builders of software has immanent properties that manifest themselves sooner or later, like rust under fresh paint. Managing the implications of those properties does not always have a good solution.
Internal state is bad, globals are worse, singletons create unbreakable bindings and make testing impossible. Massive argument lists or massive contexts are also a bad problem1.
This article is about one more technique in this space: function interfaces.
It turns out that in Kotlin, function types can be inherited by a class. Let’s take a look:
class PartialAdder(val a: Int): (Int) -> Int {
override fun invoke(b: Int): Int = a + b
}
val partial = PartialAdder(3)
partial(2) // 5!!!
This magic is due to invoke(), which makes a class instance, in essence, callable. A function type is equivalent
to an interface with an invoke function:
interface Invokable {
operator fun invoke(a: Int): Int
}
class PartialAdder(val a: Int): Invokable {
override fun invoke(b: Int): Int = a + b
}
val partial = PartialAdder(3)
partial(2) // 5!!!
Perhaps, at first it does not look like much, but consider it from the perspective of modern frameworks (Spring, etc.). You have components that depend on other components, but perhaps only use a single method of those components. The actual dependency is not on a couple components (think a repo, with a tendency to have a trillion methods), but a couple functions Yet, our mocking framework has to wrap the whole set of components, and the true dependency of your component is obscured. The above pattern (IDK what to call it: function like classes?) allows us to wrap a whole class into just the method we need, with dependencies prepackaged via injection. Mocking does not need a framework anymore. The components that can afford become more like a collection of single methods that have other methods injected. To me, it becomes a simpler, cleaner, easier to test system.