Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Kotlin Functions: Core Concepts and Syntax

Tech May 18 3

Function Declaration

Kotlin uses the fun keyword to define functions:

fun triple(number: Int): Int {
    return 3 * number
}

Function Invocation

Call standard functions using conventional syntax:

val product = triple(4)

Call member functions with dot notation:

FileReader().read() // Create FileReader instance and invoke read()

Parameters

Parameters follow Pascal notation (name: type) and require explicit types, separated by commas:

fun calculatePower(base: Int, exponent: Int) { /* implementation */ }

Default Parameters

Parameters can have default values, reducing overload count. Define defaults with = after the type:

fun write(buffer: Array<Byte>, offset: Int = 0, length: Int = buffer.size) { /* implementation */ }

Overriding methods must inherit base method defaults and omit explicit defaults in signatures:

open class Base {
    open fun greet(name: String = "Guest") { /* implementation */ }
}

class Derived : Base() {
    override fun greet(name: String) { /* implementation */ } // No default here
}

Named Arugments

Improve readability for functions with many or default parameters by specifying names:

fun reformatText(text: String,
                 lowercase: Boolean = true,
                 splitCamelCase: Boolean = false,
                 separator: Char = ' ')
                 { /* implementation */ }

// Use defaults for most parameters
reformatText(text = "SampleText", separator = '_')

Position arguments must precede named arguments, and you can spread vararg arrays with *:

fun combineStrings(vararg parts: String) { /* implementation */ }

val segments = arrayOf("first", "second")
combineStrings("prefix", *segments, "suffix")

Unit-Returning Functions

Functions returning no meaningful value have type Unit (implied if omitted):

fun logMessage(message: String?) {
    if (message != null)
        println("Log: $message")
    else
        println("Log: Empty message")
    // return Unit or return is optional
}

Single-Expression Functions

Omit braces for functions with a single expression, using = for the body. Return type is optional if inferable:

fun quadruple(value: Int): Int = value * 4
fun square(value: Int) = value * value

Explicit Return Types

Block-body functions require explicit return types (except Unit). The compiler doesn’t infer complex flow return types:

fun findMax(numbers: List<Int>): Int {
    var max = Int.MIN_VALUE
    for (num in numbers) {
        if (num > max) max = num
    }
    return max
}

Varargs

Mark the last (or only) parameter with vararg to accept variable arguments:

fun createList(vararg elements: String): List<String> {
    val list = mutableListOf<String>()
    for (elem in elements) {
        list.add(elem)
    }
    return list
}

Infix Notation

Functions marked infix (member/extension, single parameter, no vararg/default) can be called without dots/braces:

infix fun Int.multiplyBy(factor: Int): Int { /* implementation */ }

// Valid calls
6 multiplyBy 3
6.multiplyBy(3)

Local Functions

Define functions inside other functions to encapsulate logic and access closures:

fun traverseTree(tree: Tree) {
    val visited = mutableSetOf<Node>()
    fun dfs(node: Node) {
        if (!visited.add(node)) return
        for (child in node.children) {
            dfs(child)
        }
    }
    dfs(tree.root)
}

Generic Functions

Add type parameters with <> before the function name:

fun <T> wrapInList(item: T): List<T> { /* implementation */ }

Tail-Recursive Funtcions

Optimize recursive functions with tailrec (JVM/Native support), which replaces recursion with loops to avoid stack overflow:

const val PRECISION = 1E-10

// Calculates cosine's fixed point
fun findFixedPoint(start: Double = 1.0): Double {
    tailrec fun loop(current: Double): Double {
        val next = Math.cos(current)
        if (Math.abs(current - next) < PRECISION) return current
        return loop(next)
    }
    return loop(start)
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.