Summary
This incident revolves around a subtle Kotlin behavior: plus() does not mutate the original value, while += does. A junior engineer assumed both expressions were equivalent, leading to incorrect numerical results in production code.
Root Cause
The failure stems from a misunderstanding of Kotlin’s immutability model for primitive wrappers and numeric operations.
Key points:
Float.plus()returns a new Float instance- It does not modify the original variable
+=reassigns the variable to the new computed value- The engineer mistakenly believed
result.plus(...)updatedresult
Why This Happens in Real Systems
Real systems frequently hit this issue because:
- Kotlin’s numeric types are value types, not mutable containers
- Method-style arithmetic (
a.plus(b)) looks like mutation but isn’t - Developers coming from languages with mutable numeric types (e.g., some JVM libraries, C# structs) assume similar behavior
- Code reviews often miss this because the expressions look equivalent
Real-World Impact
This misunderstanding can cause:
- Silent logic errors in calculations
- Incorrect metrics or counters
- Broken financial or statistical computations
- Hard-to-debug discrepancies when values appear unchanged
Example or Code (if necessary and relevant)
var result = 0f
result.plus(1f) // returns 1f but result is still 0f
var result2 = 0f
result2 += 1f // result2 becomes 1f
How Senior Engineers Fix It
Experienced engineers address this by:
- Using
+=or explicit reassignment when mutation is intended - Avoiding method-style arithmetic unless returning the value immediately
- Writing code that makes immutability explicit, such as:
result = result + 1f
- Adding unit tests around numeric logic to catch silent failures
- Performing code reviews that focus on value semantics vs. mutation
Why Juniors Miss It
Junior engineers often overlook this because:
result.plus(...)looks like a mutating method- They assume Kotlin behaves like languages where numeric types are mutable
- They don’t yet have intuition for expression vs. statement differences
- They rely on visual similarity rather than understanding Kotlin’s type model
- They haven’t yet internalized that immutability is the default in Kotlin