RizTech Academy logo
RizTech Academy
FunctionsLesson 1 of 520 min

Defining functions and default arguments

Functions are how you name a piece of work so you can reuse it and reason about it. Kotlin's functions are more flexible than most languages', and this module is where a lot of what makes Kotlin pleasant lives. This first lesson covers the shape of a function, its parameters and return type, and the single most useful feature — default arguments.

The anatomy of a function

fun greet(name: String): String {
    return "Namaste, $name"
}

Read it left to right:

  • fun — declares a function.
  • greet — the name. Use a verb or verb phrase; a function does something.
  • (name: String) — the parameters, each written name: Type. Kotlin puts the type after the name, unlike Java or C.
  • : String — the return type, after the parameter list.
  • return ... — hands back the result.

Call it like this:

val message = greet("Kavita")
println(message)              // Namaste, Kavita

A parameter's type is always required — Kotlin cannot infer it, because a function is a contract and its inputs must be explicit. The return type you often can omit for the single-expression form (a later lesson), but for a block-body function like this one you write it, and it is good practice to write it even when inference could manage, because it documents the contract for the reader.

Functions that return nothing: Unit

A function that does something but returns no meaningful value returns Unit — Kotlin's equivalent of void:

fun logIn(user: String): Unit {
    println("$user logged in")
}

You almost never write : Unit — it is the default when you omit the return type:

fun logIn(user: String) {
    println("$user logged in")     // returns Unit implicitly
}

So "no return type written" means "returns Unit". Unit is a real type (unlike Java's void, which is a non-type), which matters when you get to higher-order functions and generics — but for now, just know that a function with no return value returns Unit, and you leave it off.

Parameters are val — always

A crucial rule that surprises people from other languages: function parameters are read-only. You cannot reassign them inside the function:

fun addTax(price: Int): Int {
    price = price + price / 10   // error: val cannot be reassigned
    return price
}

Parameters behave like val — this is the val-by-default philosophy again, and it prevents a subtle class of bug where a parameter is modified halfway through a function and later code uses the changed value by accident. If you need a modified version, make a new local val:

fun addTax(price: Int): Int {
    val withTax = price + price / 10
    return withTax
}

Default arguments — the feature you will love

This is where Kotlin functions pull ahead. A parameter can have a default value, used when the caller does not supply one:

fun greet(name: String, greeting: String = "Namaste"): String {
    return "$greeting, $name"
}

println(greet("Kavita"))                       // Namaste, Kavita
println(greet("Kavita", "Good morning"))       // Good morning, Kavita

greeting defaults to "Namaste", so callers can leave it out. This eliminates a whole category of boilerplate that other languages solve with method overloading — writing three versions of a function with different parameter lists. In Java you might write greet(name), greet(name, greeting), and greet(name, greeting, punctuation) as three separate methods. In Kotlin it is one function with defaults:

fun greet(
    name: String,
    greeting: String = "Namaste",
    punctuation: String = "!"
): String {
    return "$greeting, $name$punctuation"
}

println(greet("Kavita"))                    // Namaste, Kavita!
println(greet("Kavita", "Hello"))           // Hello, Kavita!
println(greet("Kavita", "Hello", "."))      // Hello, Kavita.

One function, many ways to call it. Defaults make functions flexible without multiplying them, and they read far better at the definition than a pile of overloads. Put parameters with defaults after those without, so callers can supply the required ones positionally.

Functions can live anywhere

Unlike Java, where every function must be a method inside a class, Kotlin lets you declare functions at the top level of a file — no class required:

// in a file Utils.kt
fun formatRupees(paise: Int): String = "₹${paise / 100}.${paise % 100}"

This is idiomatic Kotlin. A utility function that does not belong to any object should be a top-level function, not a static method on a pointless "Utils" class. You can also declare functions inside other functions (local functions), which is occasionally useful for a helper used only in one place.

Check your work

The parts of a function declaration. fun, name, parameters (name: Type), return type (: Type), body.

Where Kotlin puts the parameter type. After the name — name: String, not String name.

What a function with no return value returns. Unit, written implicitly when you omit the return type.

Whether function parameters can be reassigned. No — they are read-only (like val); make a new local val for a modified version.

What default arguments do. Give a parameter a fallback value used when the caller omits it.

What defaults replace. Method overloading — one function with defaults instead of several overloads.

Where parameters with defaults should go. After the required ones, so callers can pass the required ones positionally.

Where Kotlin functions can live. At the top level of a file (no class needed), inside a class, or inside another function.

Practice

  1. Write greet(name: String): String that returns a greeting, and call it.
  2. Try to reassign a parameter inside a function and read the compiler error. Fix it with a local val.
  3. Write a function with no return type and confirm (in the IDE) it returns Unit.
  4. Add a greeting parameter with a default and call the function both with and without it.
  5. Add a third defaulted parameter and call the function three ways (zero, one, two extra arguments).
  6. Rewrite a set of imagined overloads (send(msg), send(msg, urgent)) as one function with a default.
  7. Write a top-level formatRupees(paise: Int) function in its own file and call it from main.

Official documentation

Next: named arguments, which make those defaults even more powerful.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship