Skip to content
tezvyn:

Compare Kotlin apply and let scope functions

Source: kotlinlang.orgHardHow cards are made

Compare Kotlin apply and let scope functions
Summary

Your grasp of Kotlin scope mechanics.

Key points

Apply uses this and returns receiver for configuration; let uses it and returns lambda result for null-safe transforms.

Watch out for

Calling them interchangeable or ignoring return values.

What's really being asked

This question probes whether you understand the mechanical differences between Kotlin scope functions, specifically how the context object is exposed inside the lambda and what the overall expression evaluates to. A senior candidate should demonstrate that apply and let are not interchangeable syntactic sugar but distinct tools chosen based on whether you are configuring an object or transforming a value, and whether the caller needs the original object or the lambda result back.

The full answer

Four things in order. First, the receiver reference: apply treats the object as a lambda receiver so you access members via this, which you can usually omit; let treats the object as a lambda argument so you access it via the implicit it parameter. Second, the return value: apply returns the context object itself, while let returns whatever the last expression in the lambda evaluates to. Third, canonical use cases: use apply for object configuration or builder-style setup because you want to mutate properties and then return the configured instance; use let for null-safe transformations or to introduce a scoped variable in a long chain because you want to operate on a non-nullable copy and pass the result forward. Fourth, a concise code snippet for each that makes the distinction obvious without needing to run it.

The mistakes people make

Several patterns raise red flags. One is claiming the difference is only stylistic and that you can always swap them. Another is forgetting that apply returns the receiver, which causes bugs when you chain a transformation and accidentally discard the computed value. A third is using let for heavy receiver-member mutation, which forces repetitive it. prefixes and hurts readability compared to direct member access. A fourth is nesting scope functions without clarifying which this or it belongs to which level, creating confusion for reviewers.

What usually comes next

Interviewers often push deeper by asking when to prefer run over let, or how also differs from apply. They may ask you to refactor a deeply nested apply-inside-let block into something readable, or to explain why with exists as a non-extension alternative. Another common extension is asking about performance: scope functions are inlined so there is zero runtime overhead, and not knowing that can signal shallow understanding. They might also ask you to compare also versus apply since both return the context object but expose it differently.

A concrete example

For apply, consider val person = Person("Alice").apply { age = 30; city = "NYC" } where the block configures fields on this and the expression returns the Person instance. For let, consider val length = name?.let { it.trim().uppercase().length } where the block receives the non-null String as it and returns the Int length; if name is null the whole expression evaluates to null. These two snippets show configuration versus transformation and object return versus computed return.

Interview question

Given val result = name?.apply { trim().length } where name is String?, what is the inferred type of result and why?

  • a.Unit because apply is intended for configuration and does not propagate lambda results
  • b.Int? because the lambda's last expression is an Int and the safe call preserves nullability
  • c.String? because apply always returns the original receiver object, ignoring the lambda's final valueCorrect
  • d.String because the safe call on a non-null execution path eliminates the nullability of the returned receiver
Why?

apply returns the context object itself, so the expression yields String?, not the lambda's Int result. Option B confuses apply with let, which returns the lambda's final value.

Just read this? Test yourself on what you have been reading.

Read the original → kotlinlang.org

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on kotlin — each one lists the topics its interview covers.

See open roles