Phase 1 · FoundationsModule 4~30 min read

Operators, Ranges & Type Checks

Operators, equality, ranges, and Kotlin's smart casts.

What you'll learn

This module rounds out the basics: the operators you calculate and compare with, Kotlin's neat ranges, and the smart casts that save you from redundant type conversions.

By the end you'll be able to:

  • Use arithmetic, comparison, and logical operators
  • Tell apart structural (==) and referential (===) equality
  • Work with ranges and the in operator
  • Check types with is and benefit from smart casts

Operators

Kotlin's operators look familiar. One thing to note, coming from Python: Int division truncates — 17 / 5 is 3, not 3.4. Convert a value to Double first if you want a decimal result:

Operators.kt
val a = 17
val b = 5

println(a + b)               // 22
println(a / b)               // 3   — Int / Int truncates
println(a % b)               // 2   — remainder
println(a.toDouble() / b)    // 3.4 — convert for a decimal result

Note

Under the hood, Kotlin operators are really function calls — a + b calls a.plus(b). That's what lets you give your own types natural syntax later (Module 24, operator overloading).

== vs ===

Kotlin has two kinds of equality, and the distinction matters:

  • Structural equality == — do they have the same contents? (This calls .equals().) This is what you almost always want.
  • Referential equality === — are they the exact same object in memory?
Equality.kt
val a = "hello"
val b = "hello"

println(a == b)              // true — structural (same contents)
println("Kotlin".length == 6)// true
println(3 in 1..5)           // true — 'in' checks membership

Tip

Unlike Java — where == on objects checks reference identity and trips up beginners — Kotlin's == does the sensible thing and compares contents. Use == for values; reach for === only in the rare case you truly need object identity.

Ranges

Ranges are a lovely Kotlin feature. 1..10 creates a range you can loop over or test membership against with in. Variations let you exclude the end, count down, or step:

Range flavours

1..10

1 to 10, inclusive

1 until 10

1 to 9 (end excluded)

10 downTo 1

counts downward

1..10 step 2

1, 3, 5, 7, 9

Ranges.kt
println(3 in 1..10)              // true
println(15 in 1..10)             // false

for (i in 1..5) print(i)         // 12345
println()

for (i in 0..10 step 2) print("$i ")   // 0 2 4 6 8 10

is & smart casts

The is operator checks an object's type. Kotlin then does something clever: after an is check, it smart casts the value automatically, so you can use it as that type without an explicit cast. No more (String) x ceremony:

SmartCast.kt
fun describe(x: Any): String {
    if (x is String) {
        return "A string of length ${x.length}"   // smart cast to String
    }
    if (x is Int) {
        return "The number ${x + 1}"               // smart cast to Int
    }
    return "Something else"
}

println(describe("Kotlin"))
println(describe(42))
println(describe(3.14))

Note

For casting that might fail, prefer the safe cast as?, which returns null instead of throwing: val s = x as? String. Combined with the null-safety tools from Module 3, you handle uncertain types gracefully.

Recap & quick check

Key takeaways

  • Int / Int truncates in Kotlin — convert to Double for a decimal result.
  • Operators are function calls under the hood (a + b calls a.plus(b)).
  • == is structural (contents, via equals); === is referential (same object). Prefer ==.
  • Ranges: 1..10 (inclusive), until (exclusive end), downTo, step; test with 'in'.
  • 'is' checks a type and smart-casts the value, so no explicit cast is needed; use as? for safe casts.

Quick check

1. What is 17 / 5 in Kotlin?

2. Which operator compares contents (structural equality)?

3. What does 3 in 1..10 evaluate to?

4. What does a 'smart cast' let you skip after an 'is' check?

5. What does 'as?' do?

Great — you've got Kotlin's operators and type checks down. Next up: Module 5 — Control Flow.