Kotlin is a very feature rich language with and the subtleties of some of these features are worthy of some exploration to fully appreciate. In this ad-hoc series we’ll look at some of these, and in this article we’ll look at function references and some of the really nice tricks that we can achieve with them.
In Kotlin functions are first class and we can store the function in a variable and not just the result of a function. Moreover we can also pass around functions as arguments. Technically this is analogous to Java 8 method references, and this can be a very useful tool when it comes to delegating behaviour. Being able to delegate behaviour can make it much easier to de-couple our code, and can also make it much easier to write testable code. For Android we often hit testability issues when our code touches Android Framework and / or support library classes which may not be available in unit tests without using expensive testing frameworks such as Robolectric.
Let’s start by looking at a very simple function reference:
myFunc
takes two arguments: The first is a boolean, and the second is a function reference. myFunc
itself contains the logic that is applied to the inputs, and funcRef
is only invoked in certain circumstances. However myFunc
is completely agnostic of what funcRef
actually does. It is also completely agnostic of how someCondition
is determined, it just applies the logic around it to determine whether funcRef
should be invoked. So, even in this very simple example, we can see how we can easily separate areas of responsibility.
We can take things a little further where we have a separate function defined which matches the signature of funcRef
:
This is behaviourally identical to the first example, but we can pass in a reference to an existing function.
If we take this a step further and make myFunc
and doSomething
members of separate classes we can see how we are each of these functions is executed within the context of its own class:
What’s important to note here is that the doSomething
references a private field of its class named output
. This field is only visible to members of ClassOne
so we can see how we are able to completely switch context using this mechanism. This can really help us in separating responsibilities by delegating behaviour to specific classes which are executed within the context of their enclosing class.
I mentioned earlier that this mechanism can help when it comes to removing dependencies on Android Framework classes. Let’s consider a simple example of looking up a colour resource value. Here are two distinct implementations for obtaining a colour value from the Resources
obtained from the Context
:
ClassOne
has a dependency on Context
so will require either an Android Framework Context
instance either by being run as part of an Expresso test, or thorough a testing framework such as Robolectric, or with some mocking of both Context
and Resources
.
In contrast, ClassTwo
has been implemented using a function reference to actually resolve the colour. We can pass in a reference to the getColor
method of ther Resources
instance to delegate the behaviour to the Android framework without ClassTwo
requiring any knowledge of the framework. To test this we can just pass in any implementation which matches the signature of that method:
The more observant may have noticed that Resources#getColor
is actually deprecated in API 23. Instead we might want to use ContextCompat#getColor
which provides backwards compatibility. However this is actually a static method, and static methods are difficult to mock, so can make our code less testable. However, a static method is still a function, and we can happily pass in a reference to a static method just as easily as a member function:
Of course we now have the dependency on Context
in ClassThree
but we could apply the techniques that we’ve already looked at to abstract this away.
So we haven’t done a really deep dive, nor have we even scratched the surface of how else we can use function references. But we’ve explored how we can use them to abstract out behaviour to keep our components discrete and with clear separation of responsibilities, while also covering some techniques of how we can avoid direct dependencies on Android Framework components. We’ve also made our code easier to write unit tests for. What’s not to like about all of this?
There is no stand-alone source for this article, as all of the gists are pretty self-contained.
© 2019, Mark Allison. All rights reserved.
Copyright © 2019 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.