This episode masters the core Kotlin syntax: val and var declarations, data types and string templates, control flow with if and when, loops and ranges, functions with default arguments, plus extension functions and infix notation.

You already understood Kotlin's architecture in episode 2. Now it's time to move up a level: master the syntax you'll write every day. Episode 3 covers variables, data types, string templates, control flow, functions, and up to extension functions and infix notation.
The biggest difference from Java will be felt here: Kotlin designs its syntax to be expressive and concise. if can be an expression, when replaces switch with something far more powerful, and functions can have default arguments that eliminate overload boilerplate.
Every concept in this episode is used directly in all the following episodes, so make sure you truly understand it before moving on.
Kotlin distinguishes read-only and mutable variables: val for values that can't change after initialization, and var for values that can. Get into the habit of using val as much as possible — the code is safer and easier to reason about:
val nama = "Arman"
var umur = 26
umur = 27In the declarations above: nama can't be changed after initialization, while umur can. The compiler will reject any attempt to reassign a val variable — protection that prevents bugs at compile time.
Kotlin's basic types include Int, Long, Double, Float, Boolean, Char, and String. String templates let you insert expressions directly into text:
val produk = "kopi"
val harga = 15_000
println("Harga $produk adalah $harga rupiah")
println("Harga total: ${harga * 2}")The $produk syntax inserts a variable's value, while ${harga * 2} inserts the result of an expression. These string templates are far more comfortable than concatenation with the plus sign.
In Kotlin, if is an expression that returns a value — unlike Java, where it's only a statement:
val nilai = 75
val status = if (nilai >= 60) "Lulus" else "Tidak lulus"
println(status)Because if returns a value, you can assign it directly to a variable. There's no ternary operator in Kotlin — the if expression replaces it more clearly.
when is far more powerful than Java's switch: it can match values, ranges, types, and conditions without needing a break:
val skor = 85
when (skor) {
in 90..100 -> println("Sempurna")
in 75..89 -> println("Bagus")
in 60..74 -> println("Cukup")
else -> println("Perlu belajar lagi")
}The in 90..100 syntax uses a range that writes a range of numbers concisely. when evaluates the matching branch, and the else branch handles all other cases.
Kotlin uses for with clean iteration:
for (i in 1..5) {
println(i)
}
for (i in 10 downTo 1 step 2) {
print("$i ")
}
while (true) {
println("loop sampai break")
break
}The range 1..5 covers the numbers 1 through 5, 10 downTo 1 goes backward, and step 2 jumps by two. This combination writes expressive loops without boilerplate.
Functions in Kotlin can have default values so callers can omit optional parameters. Named parameters make calls more readable:
fun buatEmail(penerima: String, subjek: String = "Tanpa judul", cc: String? = null): String {
return "Email untuk $penerima, subjek $subjek, cc $cc"
}
val email = buatEmail(penerima = "user@example.com", subjek = "Halo")The call above uses named arguments and only mentions two of the three parameters — the others use their default values. This replaces many of the overloads you'd normally write in Java.
For simple functions, Kotlin allows a single expression body without curly braces:
fun luasPersegi(sisi: Int): Int = sisi * sisi
fun sapa(nama: String): String = "Halo, $nama!"The functions above return the result of their expression directly. With type inference, the return type can be omitted for single-expression functions, making them even more concise. You can test all the examples in this episode with kotlinc Main.kt -include-runtime -d main.jar and then run the resulting JAR.
Extension functions let you add a function to a type without changing its original definition. This is one of the most used features across the Kotlin ecosystem:
fun String.hitungKata(): Int = this.split(" ").size
val kalimat = "belajar kotlin itu menyenangkan"
println(kalimat.hitungKata())String.hitungKata() treats String as if it had a hitungKata function. The receiver this inside the body refers to the String it was called on. You'll encounter these extension functions in many libraries, including kotlinx and Android.
Functions declared with the infix keyword can be called without a dot and parentheses, creating syntax that resembles natural language:
infix fun Int.kali(angka: Int): Int = this * angka
val hasil = 6 kali 7
println(hasil)The call 6 kali 7 reads like a sentence. Infix notation is useful for functions that read naturally like this, and is used in operations like map with key-value pairs in episode 5.
Episode 3 completes your core syntax toolkit: val and var, string templates, if and when as expressions, loops with ranges, functions with default arguments, and extension functions and infix notation. All of these are tools you'll use in every following episode.
The key takeaways:
val by default, var only when you truly need it.if and when are expressions that can return values.$variable and ${expression}.In episode 4 we'll discuss classes, objects, and OOP — class declarations, constructors and properties, visibility modifiers, data classes, sealed classes, inheritance, interfaces, and companion objects and the singleton pattern. It's time to build your object world with Kotlin.