Kotlin Module 2
Values, types and control flow interview questions
Interview questions on values, types and control flow: short warm-ups, then what each harder question tests, the first step of a good answer and its follow-ups.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is the difference between val and var in Kotlin, and which should you use by default?
-
Fresher
What happens in Kotlin when an Int calculation goes past Int.MAX_VALUE?
-
Fresher
In Kotlin, what is the difference between == and === for strings, and which one should you use?
Answered in the lesson Strings, characters and string templates
-
Fresher
What is the difference between toInt() and toIntOrNull() in Kotlin, and when do you use each?
-
Fresher
Kotlin has no ternary operator. What do you write instead of Java's condition ? a : b, and what does Kotlin require of it?
-
Fresher
What is the difference between 1..10, 1..<10 and 10 downTo 1 in Kotlin?
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Fresher to mid
A class has a public property
val orders = mutableListOf<Order>(), and its author says callers cannot change it because it is a val. A week later a report lists orders that were never placed. What went wrong, and how would you expose the orders safely?- What it tests
- That val fixes the reference and not the object, the difference between a read-only view and a copy, and choosing what a class lets its callers do.
- First step
- Separate the two things val could mean. Here it only stops anyone from assigning a new list to orders; the property's type is MutableList, so any caller can still call add or clear on the one list the class keeps. Then ask what callers need: to read the orders, to watch them change, or a snapshot of one moment.
- Follow-ups
-
- Is changing the property's type to List<Order> enough?
- When would you return a copy rather than a read-only view?
- How would you test that callers cannot add orders?
From the lesson val, var and type inference
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A shared library declares
val pageSize = 50at the top level. A new version changes it toval pageSize = 50L. Some services stop compiling; others were compiled against the old version and fail only after the new library is deployed. Explain both failures and the rule that would have prevented them.- What it tests
- How inference fixes a public type, what a changed type does to callers' source and to callers that are already compiled, and the library rule of explicit types.
- First step
- Notice that nobody wrote the type, so the public type is whatever the first value gives: Int before, Long now. Then separate the two kinds of caller: code that is compiled again against the new version, and code compiled against the old one that meets the new jar only when it runs.
- Follow-ups
-
- Would const val pageSize = 50 have behaved differently?
- How do you change a public type without breaking callers?
- Which tools catch such a change before a release?
From the lesson val, var and type inference
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Fresher to mid
A scheduler computes a job's timeout in milliseconds as
(days * 24 * 60 * 60 * 1000).toLong(), where days is an Int read from a settings file. With days set to 30, every job times out at once. Explain the number the code produces, fix it, and say how you would keep the same bug out of the rest of the code.- What it tests
- Overflow inside Int arithmetic, where a conversion has to happen, and turning one fix into a rule that the code base follows.
- First step
- Work out the true value first: 30 days is 2,592,000,000 milliseconds, more than Int.MAX_VALUE, 2,147,483,647. So the timeout cannot be right if any step of the calculation ran as an Int. Find the step where it passed the limit, and what a wrapped value of that size would be.
- Follow-ups
-
- Why does the program not crash at the overflow?
- Would declaring the timeout as a Long have helped?
- How would a test or a careful reading of the code catch this kind of bug?
From the lesson Numbers, conversions and overflow
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
An expense app stores amounts as Double rupees. A user reports that ten items of 0.10 rupees add up to 0.99 rupees in an export. Explain how that can happen, then plan the move to Long paise, including the amounts already stored.
- What it tests
- Binary fractions, how cutting off a fraction turns drift into a wrong paisa, and moving stored money to whole minor units without losing any.
- First step
- Start from what a Double stores: 0.1 has no exact binary form, so each addition carries a tiny error, and the lesson's 0.1 + 0.2 already printed 0.30000000000000004. Ten such additions can land a hair below 1.00, and an export that turns rupees into paise by cutting off the fraction then shows 99 paise.
- Follow-ups
-
- Why not round every result to two decimal places instead?
- How do you convert the stored Double values without losing a paisa?
- Where would you still need BigDecimal?
From the lesson Numbers, conversions and overflow
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A bill of 40 lines carries an 18 % tax. Should the code round the tax to the paisa on every line, or once on the bill's total? Show with small numbers how the two can differ, say who decides, and how you would test it.
- What it tests
- Rounding as a business rule, half-way cases, how rounding per line and rounding the total drift apart, and testing money code with exact whole numbers.
- First step
- Take a tiny case: two lines of 1.25 rupees. 18 % of each is 22.5 paise, exactly half way, so rounding each line half up gives 23 paise twice, 46 in all, while the total, 2.50 rupees, carries exactly 45 paise. The two methods already differ by a paisa on two lines.
- Follow-ups
-
- Which rounding mode would you choose, and why?
- What would Double arithmetic add to the problem?
- How do you keep the printed lines and the total consistent for the customer?
From the lesson Numbers, conversions and overflow
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Fresher to mid
A sign-up form limits names to 20 characters with
name.length <= 20and stores the first 20 characters withtake(20). Users with Hindi names and emoji say the limit is unfair, and some stored names end in a broken character. Explain both problems and what you would count and cut instead.- What it tests
- What length counts, how Hindi syllables and emoji differ from what a reader sees, cutting at character boundaries, and naming which count a limit is about.
- First step
- Start from what length counts: UTF-16 code units, not characters. An emoji beyond U+FFFF takes two, and a Hindi syllable such as स्ते takes four, so a name a reader sees as 8 characters can use up the whole limit. Then ask what the limit is for, since the form, the database and the screen may each count differently.
- Follow-ups
-
- Which count should the form show as characters left?
- How do you cut a name without breaking a character?
- What changes if the database column limits bytes?
From the lesson Strings, characters and string templates
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
You build a JSON request body in Kotlin with a raw string template. The body must contain the key
$refand a price written as$9. The build fails with an unresolved reference. Why, what are your options, and which would you choose for a long payload?- What it tests
- How a template finds the start of a value, the ways to keep a literal dollar sign, and when to stop building JSON by hand.
- First step
- Read the error: inside a template, a $ followed by a name starts a value, so $ref asks for a variable named ref, which does not exist. $9 is not a name, so it stays as text. Any fix is a way of writing a dollar sign that the compiler does not read as the start of a value.
- Follow-ups
-
- How does a multi-dollar string decide what is a value?
- Why is building JSON with templates risky even when it compiles?
- What would you do with a regular expression that ends in $?
From the lesson Strings, characters and string templates
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid
A report job builds a 50,000-line CSV with
text += line + "\n"inside a loop, and it gets slower the longer the file grows. Explain the cost, rewrite the approach, and say what you would measure to confirm the fix.- What it tests
- Immutable strings, why repeated concatenation in a loop costs more and more, buildString and joinToString, and measuring before and after a change.
- First step
- Start from immutability: a String never changes, so every += builds a new string from the old text and the new line. Then measure how the job's time grows when the number of lines doubles, which tells you whether the cost is in the loop or somewhere else.
- Follow-ups
-
- Is a single line with several + signs a problem too?
- When would you write the lines straight to a file instead?
- How do you measure the fix without fooling yourself?
From the lesson Strings, characters and string templates
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A payments form accepts amounts typed as
1,234.50,₹ 99or12,34,567.5. Design a function that turns the text into paise, say what it refuses and why, and explain why callingtoDouble()first is the wrong start.- What it tests
- Checking shape before parsing, both digit groupings, exact conversion to whole paise, overflow, and refusals a person can act on.
- First step
- Fix the result first: a Long of paise, or a refusal with its reason. Then list the shapes you accept, with or without the rupee sign, with either grouping and with at most two digits after the point, and check that shape before converting anything, since a Double cannot hold every amount exactly.
- Follow-ups
-
- What would you do with digits from other scripts?
- How do you stop a huge amount from overflowing?
- What should the message for a refused amount say?
From the lesson Parse text and format Indian numbers
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A finance report formatted with NumberFormat for en-IN shows 12,345,678 where the finance team expects 1,23,45,678. Explain why, and how you would produce Indian grouping reliably on every server, negative amounts included.
- What it tests
- How DecimalFormat groups digits, the ways to get Indian grouping, keeping amounts as whole paise, and testing a formatter on its edge values.
- First step
- Read the documentation of DecimalFormat, which NumberFormat uses: it has one grouping size, and when a pattern has several separators only the last interval counts. So en-IN can only give groups of three, and the fix must come from code that knows two grouping sizes.
- Follow-ups
-
- Would you write the formatter yourself or add ICU4J?
- Which inputs must its tests cover?
- Where in the program should the formatting happen?
From the lesson Parse text and format Indian numbers
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A teammate wants one regular expression to validate the dates, amounts and postal codes typed into a form. When is a regular expression the right check, and when would you parse instead? Give an example where a pattern accepts text your program cannot use.
- What it tests
- Shape against meaning, validation that stays readable, checks and parsers that disagree, and limits on input.
- First step
- Separate shape from meaning. A pattern can say that a postal code is six digits not starting with 0, but not that a date exists or that an amount fits in a Long. Use one small pattern per field for the shape, then convert the value and check it in code.
- Follow-ups
-
- What goes wrong when the pattern and the parser disagree?
- How do you keep a slow pattern from hurting the service?
- What would you test?
From the lesson Parse text and format Indian numbers
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
Your team adds a new subtype to a sealed interface that fourteen when expressions across the code base read, and some of those end in else. What happens when the code is built, what happens when it runs, and what rule would you set for the team?
- What it tests
- How exhaustiveness checking treats else, which when expressions and statements must name every subtype, and turning a silent misrouting into a build error.
- First step
- Sort the when expressions into two groups: those with a branch for every subtype and no else, and those that end in else. Ask what the compiler can see in each group once the new subtype exists, and which group it cannot help you with.
- Follow-ups
-
- Why does the compiler not warn about the else branches?
- What if the sealed interface comes from a library you depend on?
- How do you find every when over the type in a large code base?
From the lesson if and when expressions
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
You are asked to replace a 60-line if-else chain that computes delivery fees with a when. How do you make sure the rewrite changes no result, and which mistakes do you look for first?
- What it tests
- Proving a refactor by comparing old and new code, choosing inputs at the boundaries, and the range, order and default mistakes of rewriting branches as when.
- First step
- Keep the old function, write the new one beside it, and plan a comparison before reading any code closely: count the possible inputs, and if there are too many, list the limits the old code tests, so you can take the values on each side of every limit.
- Follow-ups
-
- What if the old code has a bug?
- How do you choose the boundary values?
- Would a property-based test help?
From the lesson if and when expressions
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
When would you use a guard condition in a when, when a nested when inside a branch, and when a when without a subject? Give an example where the wrong choice costs you the compiler's exhaustiveness check.
- What it tests
- The three ways to add a condition to a case, what each lets the compiler check, and the else that hides a new kind of value.
- First step
- Start from what the decision is about. If it is about one value of your own sealed or enum type, keep that value as the subject so the compiler can check the cases, then decide how the extra condition attaches to one branch.
- Follow-ups
-
- Are guards slower than nested ifs?
- Can a guard use a value from an outer scope?
- When would you refactor guards into a nested when?
From the lesson if and when expressions
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A nested search over a coach's seat map must stop at the first free window seat. Would you use a labelled break, a flag variable, or a function that returns the seat? Explain the trade-offs and how you would test the search.
- What it tests
- How break acts on nested loops, labels against flags against early return, and choosing the form a reader and a test can follow.
- First step
- State what must happen at the first match: both loops end, and the seat is used afterwards. Then see what each form needs for that: a label on the outer loop, a flag tested by both loops, or a function whose return ends both.
- Follow-ups
-
- Does a labelled break cost anything at run time?
- What about firstOrNull on the rows?
- How do you test the search?
From the lesson Loops, ranges and labelled jumps
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A colleague writes break inside forEach, within a loop over days, to stop processing the rest of a day's items. In production, whole days of work go missing. Explain what the code did, why it compiled, and how you would rewrite it.
- What it tests
- Non-local break and continue in inline lambdas, what break acts on inside forEach, and choosing between return@forEach, a for loop and takeWhile by intent.
- First step
- Ask which loop the break belongs to. forEach is a function that takes a lambda, not a loop statement, so list the loops the code really has, work out which of them a break inside the lambda can end, and follow the days after the first stop item.
- Follow-ups
-
- Why was non-local break added if it causes this?
- Does return inside forEach have the same problem?
- How would you catch this before it ships?
From the lesson Loops, ranges and labelled jumps
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
Reading a colleague's change, you see for (i in 0..items.size), for (i in n..1) and pages = total / size. Which of these are bugs, what does each do when it runs, and how would you write each one?
- What it tests
- Closed against half-open ranges, empty ranges that count the wrong way, integer division of page counts, and boundary tests.
- First step
- Run each one in your head on a small case: three items, n = 10, and 103 results at 25 a page. Write down what each loop visits, or what the count comes to, and compare it with what the code was meant to do.
- Follow-ups
-
- Why does the compiler not warn about n..1?
- Is 0 until n the same as 0..<n?
- What about a list that can be empty?
From the lesson Loops, ranges and labelled jumps
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 2 minutes