Overview

3 Programming with functions

This chapter reframes programming as the composition of pure functions, urging a clear separation between deterministic computations and interactions with the outside world. It grounds the idea of a function in its mathematical meaning—a total, single-valued relationship from a domain to a codomain—then uses that lens to explain purity, determinism, and testability. Along the way it distinguishes total from partial functions (and why bugs often stem from treating partials as totals), shows how and why inverses may not exist, and introduces composition as a first-class operation where order matters. Multi-argument routines are recast as single-argument functions over tuples, paving the way to currying and the practical benefits of partial application.

On the Kotlin side, the text separates “fun” declarations (efficient subprograms) from value functions (lambdas with function types) that can be stored, passed, and returned. It demonstrates function references, composing functions as data, and building higher‑order and polymorphic combinators (such as compose and andThen). The chapter shows how to curry and partially apply functions, swap argument order when needed, and leverage anonymous and local functions, all while respecting type inference limits and using explicit annotations when the compiler needs help. It also examines closures and referential transparency, explaining how dependencies on enclosing scope act like implicit parameters and how to make those dependencies explicit for clarity, safety, and reuse.

Practically, the chapter promotes immutability, pure error handling (returning values instead of throwing), and explicit, domain‑centric types. It introduces the identity function for composition, contrasts reduce with fold, and underscores how curried, partially applied functions improve modularity and reuse. A capstone example replaces primitive doubles with value types (Price, Weight), defines safe operators, and folds collections with neutral elements to eliminate category errors the compiler cannot catch with raw primitives. Throughout, the guidance emphasizes choosing the right types, isolating effects, and relying on the type system to construct safer, more testable Kotlin programs built from small, composable functions.

Figure 3.1. All elements of a function’s domain must have one and only one corresponding element in the codomain.
Fig03 01

 Summary

  • A function represents a relationship between a source set and a target set. It establishes a correspondence between the elements of the source set (the domain) and the elements of the target set (the codomain).
  • Pure functions have no visible effects beside returning a value.
  • Functions have only one argument, which can be a tuple of several elements.
  • You can curry functions of tuples in order to apply them to one element of the tuple at a time.
  • When a curried function is applied to only some of its arguments, it’s said to be partially applied.
  • In Kotlin, functions can be represented by fun functions, which are methods, or by value functions, which can be handled as data.
  • Value functions can be implemented by using lambdas or by using references to fun functions.
  • You can compose functions to create new functions.
  • You can use lambdas and function references in places where a value function is expected.
  • You can use value types to make programs safer by allowing the compiler to detect type problems.

FAQ

What is a pure function and why does it matter in Kotlin?It’s a function that depends only on its inputs, always returns a value, does not mutate external state or its parameters, and does not throw. Pure functions are deterministic and easy to test, making programs safer and more maintainable.
How are Kotlin “functions” different from mathematical functions and Java methods?Kotlin’s fun declarations are methods that may be pure or impure. Mathematical functions are precise mappings (A) → B. In Kotlin you can also treat functions as data via function types (e.g., (Int) → Int) and lambdas, allowing passing, returning, and storing functions.
What is function composition and how does order matter?Composition builds a new function by applying one function to the result of another: f ∘ g means x ↦ f(g(x)). Order matters: generally f ∘ g ≠ g ∘ f. In Kotlin you can write compose(f, g) or define curried versions like higherCompose() and the reverse higherAndThen().
What are total and partial functions in this chapter’s sense?A total function is defined for every value of its domain; a partial function isn’t (e.g., Int division by zero). You can often make a partial function total by extending the codomain to include an error value (later modeled with types like Option/Either).
What is currying and how does it relate to partial application?Currying transforms a tupled function (A, B) → C into (A) → (B) → C. This enables partial application: supply one argument to get a new function waiting for the next (e.g., fixing a rate to get a reusable “apply tax” function).
What are higher‑order functions (HOFs) and when should I use value functions vs fun?HOFs take functions as parameters or return them. Use value functions (function types/lambdas) when you need to pass, return, or store behavior. Use fun methods for efficient direct calls. You can bridge with function references (e.g., ::square) when needed.
How do function references (::) work in Kotlin?Use ::name for top-level or same-scope functions, instance::method for instance methods, and (MyClass)::func or MyClass.Companion::func for companion members. Note that MyClass::func (without .Companion or parentheses) often yields a receiver-in-first-parameter type (e.g., (MyClass, Int) → Int).
What are closures in Kotlin and do they break purity?A closure is a function that captures variables from its surrounding scope (e.g., using a taxRate defined outside). This is pure if the captured values are treated as immutable “implicit parameters.” To improve clarity and modularity, prefer making such parameters explicit or use currying.
How should I think about multi‑argument functions in Kotlin?There are no true multi‑argument functions—only single‑argument functions over tuples (e.g., (A, B)) or curried chains (A) → (B) → C. Kotlin has Pair/Triple, but curried forms enable partial application and utilities like swapping argument order.
Why use domain value types (Price, Weight) instead of primitives like Double?Primitive reuse invites bugs (e.g., adding weights to prices). Define value types (e.g., data class Price, Weight) with operators, validation (private constructor + companion invoke), and identity elements. Then aggregate with fold, and the type system prevents mixing incompatible quantities.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Joy of Kotlin ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Joy of Kotlin ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Joy of Kotlin ebook for free