skip to content

Misc Helpers

The small stdlib helpers that show up everywhere: conditional scoping with takeIf, TODO and repeat, bitwise functions, and the multiplatform Random. Individually trivial, collectively a good signal of stdlib fluency.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

explore

questions

21

How do you perform bitwise operations in Kotlin, and how does this differ syntactically from Java?

level: juniorimportance: must knowfreq 55%

answer

  1. No &|^~<<>> symbols in Kotlin
  2. and/or/xor/shl/shr/ushr are infix functions
  3. inv() is a member, not infix (unary)
  4. Only on Int/Long (and unsigned types)
  5. Parenthesize when mixing with arithmetic/comparison

basics

~20 s

Kotlin has no &, |, ^, <<, >> symbols. Instead it uses named infix functions like and, or, xor, shl, shr on Int and Long. So you write a and b instead of a & b.

solid answer

~40 s

Kotlin deliberately omits Java's bitwise operator symbols (&, |, ^, ~, <<, >>, >>>). Instead, the standard library defines named infix functions on Int and Long: and, or, xor, inv (replaces ~), shl (signed left shift), shr (signed/arithmetic right shift), and ushr (unsigned/logical right shift). You call them infix-style: 0xF0 and 0x0F, 1 shl 4, x.inv(). inv() is a regular member function, not infix, because it is unary. These functions only exist on Int and Long (and the unsigned types) — Byte and Short get promoted to Int first. Because they are normal function calls, they bind with lower precedence than arithmetic, so parentheses are often needed: (a shl 2) + 1.

code

kotlin · 8 lines
kotlin
val a = 0b1100
val b = 0b1010
println(a and b) // 8  (0b1000)
println(a or b)  // 14 (0b1110)
println(a xor b) // 6  (0b0110)
println(a.inv()) // -13 (all bits flipped)
println(1 shl 4) // 16
println((a shl 1) + 1) // parentheses needed

go deeper

for a junior

Knows the symbol-to-word mapping and that you write 'a and b', 'a shl b'.

for a middle

Explains inv() is a member not infix, that only Int/Long support them, and the precedence pitfall.

for a senior

Discusses Byte conversion/masking and why parentheses matter when mixing with comparison/arithmetic.

for a principal

Reasons about API design tradeoffs of readable infix vs symbolic operators and impact on DSLs/readability.

## Why Kotlin uses words, not symbols Unlike Java/C, Kotlin does **not** reserve the punctuation operators `&`, `|`, `^`, `~`, `<<`, `>>`, `>>>` for bit manipulation. The language designers freed those tokens (some are used elsewhere or reserved), and instead expose bit operations as **named infix functions** in the standard library. An **infix function** is a function marked with the `infix` keyword that can be called without the dot and parentheses: `a shl b` is exactly `a.shl(b)`. ## The full mapping (Java symbol -> Kotlin function) - `a & b` -> `a and b` - `a | b` -> `a or b` - `a ^ b` -> `a xor b` - `~a` -> `a.inv()` (member function, NOT infix — it's unary) - `a << b` -> `a shl b` (shift left) - `a >> b` -> `a shr b` (arithmetic / signed right shift) - `a >>> b`-> `a ushr b` (logical / unsigned right shift) ## Where they live These functions are declared **only on `Int` and `Long`** (plus the unsigned `UInt`/`ULong`). There are no bitwise functions on `Byte`, `Short`, `Char`, `Float`, or `Double`. To bit-twiddle a `Byte` you first convert: `byteVal.toInt() and 0xFF`. ```kotlin val flags = 0b0000 val READ = 1 shl 0 // 1 val WRITE = 1 shl 1 // 2 val combined = READ or WRITE // 3 val hasWrite = combined and WRITE != 0 // careful with precedence! val cleared = combined and WRITE.inv() // remove WRITE bit ``` ## Precedence gotcha Because infix functions are ordinary calls, they have **lower precedence than arithmetic** and named-infix calls are left-associative with each other but bind looser than `+`, `*`, and comparison can be surprising. `combined and WRITE != 0` parses as `combined and (WRITE != 0)` which won't even compile (type mismatch); write `(combined and WRITE) != 0`. Always parenthesize when mixing shifts/masks with arithmetic or comparisons. ## Summary The semantics are identical to Java's bit operators on the same two's-complement 32/64-bit integers; only the surface syntax changed from symbols to readable words.

  • Why is inv() not an infix function?
    infix functions must take exactly one parameter besides the receiver. Bitwise NOT is unary (only a receiver, no argument), so it's a plain member function called with dot syntax: x.inv().
  • Can you use these on a Byte?
    No. Byte/Short have no bitwise functions. Convert with toInt() first, and usually mask with and 0xFF to avoid sign extension before operating.

Kotlin spells the bit operators out in words the way a calculator labels buttons 'AND'/'OR' instead of cryptic symbols.

saying these in an interview costs you the question

  • Claiming Kotlin supports & | ^ << >> operators like Java
  • Saying inv() is infix or writing 'a inv b'
  • Thinking Byte/Short have bitwise functions directly
  • Forgetting parentheses so 'mask and x != 0' fails to compile
  • Confusing shr and ushr

context

open as a page

How do you generate a random integer within a specific range (e.g. 1 to 6 inclusive) using Kotlin's standard library, and which class do you use?

level: juniorimportance: must knowfreq 70%

basics

~10 s

Use kotlin.random.Random. Call Random.nextInt(1, 7) to get a number from 1 up to but not including 7. The lower bound is included, the upper bound is excluded.

open as a page

What do takeIf and takeUnless do, and what does each return?

level: juniorimportance: must knowfreq 55%

basics

~10 s

takeIf returns the value if a condition is true, otherwise null. takeUnless is the opposite: it returns the value if the condition is false, otherwise null.

open as a page

What does repeat(n) { } do in Kotlin, and what argument does its lambda receive?

level: juniorimportance: must knowfreq 55%

basics

~10 s

repeat(n) runs the block of code n times. Each run, the block gets the current count, starting at 0, so you know which iteration you're on.

open as a page

What does the Kotlin standard-library function TODO("...") do, and what happens at runtime if execution reaches it?

level: juniorimportance: must knowfreq 60%

basics

~10 s

TODO marks code you haven't written yet. If the program runs that line, it crashes by throwing an error, reminding you to finish it.

open as a page

What is the difference between shr and ushr in Kotlin, and when does it actually matter?

level: middleimportance: must knowfreq 50%

basics

~10 s

shr keeps the sign: shifting a negative number right fills the top bits with 1s. ushr ignores the sign and always fills the top bits with 0s. They only differ for negative numbers.

open as a page

Show how takeIf chained with the Elvis operator expresses a conditional value, and explain why this is preferred over an if/else here.

level: middleimportance: must knowfreq 50%

basics

~10 s

Use value.takeIf { condition } ?: fallback. If the condition holds you get the value, otherwise the fallback. It reads as one fluent expression instead of a multi-line if/else.

open as a page

Show how to implement a bit-flag set in Kotlin: setting, clearing, toggling, and testing a flag using the infix bit functions.

level: middleimportance: should knowfreq 45%

basics

~10 s

Use one bit per flag. Set a flag with 'or', clear it with 'and' of the inverted mask, toggle with 'xor', and test it with 'and' then compare to zero.

open as a page

What do the random() and shuffled() collection extensions do in Kotlin, and how can you control which generator they use?

level: middleimportance: should knowfreq 60%

basics

~10 s

list.random() returns one random element; list.shuffled() returns a new list with the elements in random order. Both have overloads taking a Random instance so you can pass a seeded generator.

open as a page

How do you make random number generation reproducible in Kotlin, and why would you want a seeded generator instead of the default one?

level: middleimportance: should knowfreq 55%

basics

~10 s

Create a generator with a fixed seed using Random(seed). Two generators built with the same seed produce the same sequence of numbers, which is great for repeatable tests and debugging.

open as a page

How do takeIf and takeUnless differ from let, run, and a filter on a single value? When would you reach for each?

level: middleimportance: should knowfreq 40%

basics

~10 s

takeIf/takeUnless decide whether to keep a value (returning it or null). let/run transform a value into something else. filter works on collections, not single values. Use takeIf to conditionally keep, let to map.

open as a page

Since repeat is inline, what does this enable inside its lambda — for example, can you `return` from the enclosing function within repeat { }? Contrast it with break/continue.

level: middleimportance: should knowfreq 30%

basics

~10 s

Because repeat's body is inlined, a plain return inside it actually returns from the surrounding function. But break and continue don't work like in a normal loop; you simulate continue with return@repeat.

open as a page

How does TODO()'s Nothing return type interact with control-flow analysis, such as when used in a branch of a when or as a default elvis fallback?

level: middleimportance: should knowfreq 35%

basics

~10 s

Because TODO() never returns normally, the compiler knows code after it can't run. So you can drop it into a branch that needs a value, or after ?:, and the types still line up.

open as a page

What do countOneBits, countLeadingZeroBits, and countTrailingZeroBits do on Int/Long, and what are typical uses?

level: seniorimportance: should knowfreq 30%

basics

~10 s

They count bits in a number: countOneBits counts the 1s (population count), countLeadingZeroBits counts zeros before the first 1 from the left, and countTrailingZeroBits counts zeros after the last 1 from the right.

open as a page

What are Kotlin's unsigned integer types (UInt/ULong), how do they relate to bitwise work, and what should you watch out for?

level: seniorimportance: should knowfreq 28%

basics

~20 s

UInt and ULong are integer types that hold only non-negative values by reinterpreting the sign bit as magnitude. They make bit work clearer because right shift never sign-extends, and printing/comparison treat the value as unsigned.

open as a page

When is kotlin.random.Random inappropriate, and what concurrency and security considerations apply when using random generators in production Kotlin code?

level: seniorimportance: should knowfreq 45%

basics

~10 s

kotlin.random.Random is predictable, so never use it for passwords, tokens, or keys — use a secure generator like SecureRandom. Also, the default generator is thread-safe but a custom seeded one may not be.

open as a page

Explain the nullability and smart-cast implications of takeIf, including pitfalls when the receiver is already nullable or when chaining several takeIf calls.

level: seniorimportance: should knowfreq 30%

basics

~10 s

takeIf always returns a nullable type, even on a non-null receiver. On a nullable receiver use ?.takeIf so the predicate sees a non-null it. Chaining many takeIf calls layers nullability and hurts readability.

open as a page

How does TODO() differ from error(), check()/require(), and an empty stub body? When would you choose each, and what are the design implications of shipping TODO() to production?

level: seniorimportance: should knowfreq 25%

basics

~20 s

TODO() means 'not built yet' and crashes if hit. error() means 'this should never happen'. require/check validate inputs/state. An empty body silently does nothing. Pick based on intent; never leave a live TODO() for users.

open as a page

Beyond nextInt, what other primitive random values can kotlin.random.Random produce, and what are the bound semantics for nextDouble?

level: middleimportance: nice to knowfreq 40%

basics

~10 s

Random can produce Long, Double, Float, Boolean, Int, and random bytes. nextDouble() returns a value from 0.0 up to (but not including) 1.0; overloads let you set bounds.

open as a page

When should you reach for repeat(n) versus a for-loop or value builders like List(n) { } / (0 until n).map { }? Discuss intent, value production, and performance.

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

Use repeat for a fixed number of side-effecting passes when you don't need to collect results. If you need a list of computed values, use List(n) { }. If you need to break early or complex stepping, use a for-loop.

open as a page

Implement takeIf yourself and discuss its design: the inline/contract considerations and when its use harms readability.

level: principalimportance: nice to knowfreq 18%

basics

~10 s

takeIf is a tiny inline extension: if the predicate is true return this, else null. It is inline so the lambda doesn't allocate. Overusing it for complex logic hurts clarity, so prefer if/when there.

open as a page