Idiomatic Kotlin: Local functions
This article is a part of the Idiomatic Kotlin series. The complete list is at the bottom of the article.
In this article, we will be talking about local functions and how we can use it in conjunction with Extension functions.
What is a local function?
A local function is a function within a function. Yes you heard that right. It is a function scoped within another function. It is another way to achieve code reuse.
Motivation
Reusable sequences of code are often times extracted to another function to achieve reusability. However, this approach could easily end you up with a class littered with small functions with no clear relationship between each other. Grouping these functions could also net you a lot of boilerplate code. Wouldn’t it be nice to extract these functions and scope them to the function that requires them to make relationships clear without any boilerplate code?
How to create a local function?
Creating a local function is as simple as declaring a variable but this time with the fun
keyword.
Local functions must be declared first before they are referenced. Think of it as declaring a variable first before using it. Local functions can also reference the variables local to the function. Let’s see how it is done under the hood.
Local functions under the hood
Let us decompile the above source code.
The local variables are converted to a Ref
type available in the kotlin JVM. This allows you to somehow pass (or access) by reference. This feature is called capturing. It allows you to modify non-final variables by wrapping it in a reference. Let’s take a look at where the magic happens.
The local function is represented as a Function
object and is called via a method invoke
. If you are familiar with functional interfaces, higher-order functions and lambda expressions, then you can say that this is the pre-Java 8 way of achieving those.
Performance overhead
There are things to consider when using local functions. Some are pretty negligible but it is good to know them.
First on the list is the added classes and objects. A function, depending on how it is declared, can be instantiated (or define a class) as many as there are calls to it.
Another overhead is the added function count. A Function
adds more than a direct private function definition towards the DEX function count, which makes you closer to the limit (when working with Android). Kotlin has a nice feature to minimize this called inlining but it does not apply to local functions. Inline
will be discussed in a future article.
Use with extension function
Local functions can be converted to an extension function. Let us use the code above as an example.
A credential class is created to wrap username and password. Then, a validate function is created as an extension function to validate the credential object. This is useful in cases wherein you do not want to pollute the data class with private functions only a the login package will use.
Check out the other articles in the idiomatic kotlin series. The sample source code for each article can be found here in Github.
- Extension Functions
- Sealed Classes
- Infix Functions
- Class Delegation
- Local functions
- Object and Singleton
- Sequences
- Lambdas and SAM constructors
- Lambdas with Receiver and DSL
- Elvis operator
- Property Delegates and Lazy
- Higher-order functions and Function Types
- Inline functions
- Lambdas and Control Flows
- Reified Parameters
- Noinline and Crossinline
- Variance
- Annotations and Reflection
- Annotation Processor and Code Generation