Implement both `compose` and `andThen` as infix extensions on function types and explain why the generic signatures differ in argument order.
answer
- andThen receiver = (A)->B (input side); compose receiver = (B)->C (output side)
- a andThen b == b compose a
- Intermediate type B is the contact point both share
- Associative, not commutative
- compose mirrors math (f ∘ g)(x) = f(g(x))
basics
~10 sandThen runs the receiver first; compose runs the argument first. Their type parameters differ because the receiver and argument swap which function produces the intermediate value the other consumes.
solid answer
~40 sBoth are `infix` extensions returning a new lambda. `andThen` reads left-to-right: the receiver `(A)->B` runs first, the argument `(B)->C` consumes its output, result `(A)->C`. `compose` follows the math convention `(f ∘ g)(x) = f(g(x))`: the receiver `(B)->C` runs last, the argument `(A)->B` runs first, result `(A)->C`. The signatures differ because in `andThen` the receiver is the *input-side* function (`(A)->B`), while in `compose` the receiver is the *output-side* function (`(B)->C`). The intermediate type B is always wired so one function's output matches the other's input; the compiler enforces this. Both bodies just capture the two functions in a closure and defer execution until invoked.
code
kotlin · 7 linesinfix fun <A, B, C> ((A) -> B).andThen(g: (B) -> C): (A) -> C = { g(this(it)) }
infix fun <A, B, C> ((B) -> C).compose(g: (A) -> B): (A) -> C = { this(g(it)) }
val inc: (Int) -> Int = { it + 1 }
val dbl: (Int) -> Int = { it * 2 }
println((inc andThen dbl)(3)) // (3+1)*2 = 8
println((inc compose dbl)(3)) // (3*2)+1 = 7go deeper
Can write andThen; may need help articulating why compose's receiver type differs.
Writes both correctly, explains the receiver-side difference and the a andThen b == b compose a identity.
Adds associativity/non-commutativity, discusses readability trade-offs, and the type-safety role of the generics.
Relates these to standard FP laws and decides team conventions (prefer andThen pipelines) for maintainability.
## The two directions There are two standard ways to glue `f` and `g` together, and they differ only in *reading order*: | Helper | Receiver runs | Result `(x)` | |---|---|---| | `andThen` | first | `g(f(x))` | | `compose` | last | `f(g(x))` | ## The implementations ```kotlin infix fun <A, B, C> ((A) -> B).andThen(g: (B) -> C): (A) -> C = { x -> g(this(x)) } // this = (A)->B runs first infix fun <A, B, C> ((B) -> C).compose(g: (A) -> B): (A) -> C = { x -> this(g(x)) } // this = (B)->C runs last ``` ## Why the type parameters swap roles The **receiver** (`this`) is what you call the helper *on*. The trick is which side of the data flow the receiver sits on: - In **`andThen`**, the receiver is the **first/input-side** function, so it must accept `A` and produce the intermediate `B`: receiver type `(A) -> B`. The argument then takes `B` to `C`. - In **`compose`**, the receiver is the **last/output-side** function, so it must accept the intermediate `B` and produce `C`: receiver type `(B) -> C`. The argument takes `A` to the intermediate `B`. In both cases the **intermediate type `B`** is the contact point: one function's return type must equal the other's parameter type. The generics force this — pass mismatched functions and it won't compile. This is the safety payoff of threading `A, B, C`. ## Equivalences ```kotlin // These produce identical behavior: val p1 = f andThen g // g(f(x)) val p2 = g compose f // g(f(x)) ``` So `a andThen b == b compose a`. Pick whichever reads better. Most Kotlin code prefers `andThen` because left-to-right matches how data flows in a pipeline. `compose` exists for parity with mathematical/functional notation. ## Gotchas - Function composition is **associative**: `(f andThen g) andThen h == f andThen (g andThen h)`. - It is **not commutative**: order matters. - Both are lazy — they build a closure and run nothing until called.
- Why does the receiver type differ between andThen and compose?Because the receiver sits on opposite ends of the pipeline: in andThen it's the first function (A)->B; in compose it's the last function (B)->C.
- Is `f andThen g` ever equal to `g compose f`?Always, by definition. Both evaluate to g(f(x)). They're just two notations for the same composition.
saying these in an interview costs you the question
- Gives both helpers the same receiver type, missing why they differ
- Claims composition is commutative
- Cannot explain that B is the shared intermediate type
- Writes compose as g(f(x)) (that's andThen's behavior)
- Says the generics are optional decoration rather than the source of type safety