Blog Infos
Author
Published
Topics
, , ,
Published

Photo by cindy fernandez on Unsplash

Imagine your code isn’t just a set of instructions, but a recipe book. Some recipes are simple: “Add sugar, stir.” But what if you could have a recipe for a cookie maker, where you just hand it another recipe — say, for chocolate chip or oatmeal — and it follows your instructions perfectly? This is the core idea behind higher-order functions and lambdas in Kotlin.

What’s what? Lambdas vs. higher-order functions

Though a lot goes behind the scenes but let’s just keep it simple and understand it with an analogy, Kitchen in this case coz we have to take care of hunger as well.

Let’s start with a our analogy:

  • Lambda: A function literal, or an anonymous, unnamed function. Think of it as a handwritten note with a mini-recipe: “Mix flour and chocolate chips.” It’s the action itself, concise and to the point.
  • Higher-Order Function: A function that takes another function as a parameter or returns one. This is your high-tech appliance, like a programmable cookie maker. You give it your “chocolate chip” lambda, and it knows exactly what to do.
A coffee machine with a personality

A typical coffee machine follows a set routine. It knows how to make espresso, latte, or cappuccino. But what if you want to perform an extra, custom step, like adding a special sprinkle of cinnamon or a dollop of cream?

The rigid, old-school way

fun makeEspresso() {
grindBeans()
pressHotWater()
serve()
}

 

This is fine, but what if a user wants to customize their drink? We’d have to create a new function for every possible variation, leading to a lot of repeated code.

The functional, higher-order way

Let’s upgrade our machine. We’ll give it a main brewCoffee function that can accept a custom “finishing touch”.

// This is a lambda. A function literal with no name.
val addCinnamon = { println("Adding a pinch of cinnamon.") }

// Our higher-order function, brewCoffee, takes a function as an argument.
fun brewCoffee(finishingTouch: () -> Unit) {
grindBeans()
pressHotWater()
finishingTouch() // Calling the function we were given
serve()
}

// Now we call our high-tech coffee machine!
brewCoffee(addCinnamon) // Making a coffee with cinnamon
brewCoffee { println("Adding a dollop of whipped cream.") } // A new, on-the-fly lambda

 

Our brewCoffee function doesn’t care what the final step is, as long as it’s a function that takes no parameters and returns nothing (() -> Unit). This makes our machine—and our code—incredibly flexible.

Structural patterns with functions: The template method

Design patterns are reusable solutions to common problems in software design. The Template Method pattern is a classic structural pattern. It defines the skeleton of an algorithm in a base class but lets subclasses override certain steps. With higher-order functions, we can achieve this same flexibility without creating a new class for every small variation.

The old-school class-based approach

abstract class CookieMaker {
fun makeCookie() {
mixIngredients()
shapeDough()
bake()
decorate() // This step varies
}

abstract fun decorate()
}

class ChocolateChipCookieMaker : CookieMaker() {
override fun decorate() {
println("Adding extra chocolate chips.")
}
}

For every new cookie type, we need a new class.

The higher-order function approach

Let’s refactor our cookie maker using higher-order functions. The core logic remains the same, but the variable part is now a lambda.

fun makeCookie(decoration: () -> Unit) {
    mixIngredients()
    shapeDough()
    bake()
    decoration() // Calling the lambda for decoration
}

// Now we can make a variety of cookies without new classes!
makeCookie { println("Adding frosting and sprinkles.") }
makeCookie { println("Rolling in cinnamon sugar.") }

Reified: The real, real-life bonus

What happens if our lambda needs to inspect the type of an object, say, to see if a cookie is chocolate chip or oatmeal? As our previous thread mentioned, Kotlin and Java use type erasure with generics.

This means a generic function can’t normally see the type of T at runtime. But with inline and reified, we can get that information back.

The old-school way (with type erasure)

fun <T> isCookieType(cookie: Any, type: Class<T>): Boolean {
return type.isInstance(cookie) // Works, but requires reflection and passing the class
}

The reified way (with compile-time type information)

data class Cookie(val name: String)
data class OtherSnack(val name: String)

inline fun <reified T> bakeAndInspect(cookie: Any) {
if (cookie is T) { // This now works because of `reified`
println("It's a ${T::class.simpleName}! Delicious!")
} else {
println("It's a different kind of snack.")
}
}

fun main() {
val chocolateChip = Cookie("Chocolate Chip")
val oatmeal = OtherSnack("Oatmeal")

bakeAndInspect<Cookie>(chocolateChip) // Output: It's a Cookie! Delicious!
bakeAndInspect<Cookie>(oatmeal) // Output: It's a different kind of snack.
}

This is a powerful feature that lets you create cleaner, more readable, and type-safe APIs, often seen in libraries for tasks like JSON serialization and dependency injection.

A snippet of how GSON uses it in their use case;

import com.google.gson.Gson

// Reified allows us to get the class from the generic type T
inline fun <reified T> Gson.fromJson(json: String): T {
    return this.fromJson(json, T::class.java)
}

// Now the usage is much cleaner and more concise
val user: User = gson.fromJson(json)
val product: Product = gson.fromJson(json)

In this scenario, the reified keyword retains the User or Product type information at compile time, and the inline keyword ensures the code is efficiently inlined. This lets the fromJson extension function use T::class.java to get the necessary class reference without you ever needing to pass it explicitly.

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

, ,

Kobweb:Creating websites in Kotlin leveraging Compose HTML

Kobweb is a Kotlin web framework that aims to make web development enjoyable by building on top of Compose HTML and drawing inspiration from Jetpack Compose.
Watch Video

Kobweb:Creating websites in Kotlin leveraging Compose HTML

David Herman
Ex-Googler, author of Kobweb

Kobweb:Creating websites in Kotlin leveraging Compose HTML

David Herman
Ex-Googler, author o ...

Kobweb:Creating websites in Kotlin leveraging Compose HTML

David Herman
Ex-Googler, author of Kob ...

Jobs

Conclusion

Higher-order functions and lambdas in Kotlin move programming toward a functional paradigm, allowing you to write more expressive, concise, and reusable code. By embracing this approach, you can refactor classic design patterns into more elegant solutions, like our customizable cookie maker. And with the reified keyword, Kotlin provides a way to get the best of both worlds, offering the power of generic types with the clarity of runtime type information. So go ahead, write your code and pass in a little function to make it special.

 

This article was previously published on proandroiddev.com

Menu