From 564bc43e41bbb81fc64c0ed42d090363783767e7 Mon Sep 17 00:00:00 2001 From: "Aleksey.Zamulla" Date: Mon, 17 Feb 2025 13:46:30 +0100 Subject: [PATCH 1/3] fix: better examples, try 1 --- docs/topics/functions.md | 265 ++++++++++++++++++++++++++++++--------- 1 file changed, 206 insertions(+), 59 deletions(-) diff --git a/docs/topics/functions.md b/docs/topics/functions.md index 7d231d1b871..38f461f2e14 100644 --- a/docs/topics/functions.md +++ b/docs/topics/functions.md @@ -3,9 +3,19 @@ Kotlin functions are declared using the `fun` keyword: ```kotlin -fun double(x: Int): Int { - return 2 * x +//sampleStart +// Doubles the given number +fun double(number: Int): Int { + return 2 * number } + +fun main() { + val input = 5 + val result = double(input) + println(result) + // Prints: 10 +} +//sampleEnd ``` ## Function usage @@ -13,13 +23,39 @@ fun double(x: Int): Int { Functions are called using the standard approach: ```kotlin -val result = double(2) +//sampleStart +fun main() { + // Calls the double function with different arguments + val result1 = double(2) + val result2 = double(10) + + println(result1) + // Prints: 4 + println(result2) + // Prints: 20 +} +//sampleEnd ``` Calling member functions uses dot notation: ```kotlin -Stream().read() // create instance of class Stream and call read() +//sampleStart +class TextReader { + // Reads text from a source and returns it as a string + fun readText(): String { + return "Sample text" + } +} + +fun main() { + // Creates an instance of TextReader and calls readText() + val reader = TextReader() + val text = reader.readText() + println(text) + // Prints: Sample text +} +//sampleEnd ``` ### Parameters @@ -172,7 +208,23 @@ fun printHello(name: String?): Unit { The `Unit` return type declaration is also optional. The above code is equivalent to: ```kotlin -fun printHello(name: String?) { ... } +//sampleStart +// Prints a greeting message based on the provided name +fun printHello(name: String?) { + if (name != null) + println("Hello $name") + else + println("Hi there!") +} + +fun main() { + printHello("Alice") + // Prints: Hello Alice + + printHello(null) + // Prints: Hi there! +} +//sampleEnd ``` ### Single-expression functions @@ -202,12 +254,28 @@ in the body, and the return type will be non-obvious to the reader (and sometime You can mark a parameter of a function (usually the last one) with the `vararg` modifier: ```kotlin -fun asList(vararg ts: T): List { - val result = ArrayList() - for (t in ts) // ts is an Array - result.add(t) - return result +//sampleStart +// Creates a list from a variable number of elements +fun createList(vararg elements: T): List { + val resultList = ArrayList() + // Iterates through the elements array and adds each to the list + for (element in elements) { + resultList.add(element) + } + return resultList +} + +fun main() { + // Creates lists with different numbers of elements + val numbers = createList(1, 2, 3, 4, 5) + println(numbers) + // Prints: [1, 2, 3, 4, 5] + + val fruits = createList("apple", "banana", "orange") + println(fruits) + // Prints: [apple, banana, orange] } +//sampleEnd ``` In this case, you can pass a variable number of arguments to the function: @@ -227,16 +295,23 @@ When you call a `vararg`-function, you can pass arguments individually, for exam an array and want to pass its contents to the function, use the *spread* operator (prefix the array with `*`): ```kotlin -val a = arrayOf(1, 2, 3) -val list = asList(-1, 0, *a, 4) -``` - -If you want to pass a [primitive type array](arrays.md#primitive-type-arrays) -into `vararg`, you need to convert it to a regular (typed) array using the `toTypedArray()` function: - -```kotlin -val a = intArrayOf(1, 2, 3) // IntArray is a primitive type array -val list = asList(-1, 0, *a.toTypedArray(), 4) +//sampleStart +fun main() { + // Creates a regular array of strings + val colors = arrayOf("red", "green", "blue") + // Creates a list with additional elements before and after the array + val colorList = createList("purple", "yellow", *colors, "orange") + println(colorList) + // Prints: [purple, yellow, red, green, blue, orange] + + // Creates a primitive type array of integers + val numbers = intArrayOf(1, 2, 3) + // Converts primitive array to regular array and creates a list + val numberList = createList(0, *numbers.toTypedArray(), 4, 5) + println(numberList) + // Prints: [0, 1, 2, 3, 4, 5] +} +//sampleEnd ``` ### Infix notation @@ -250,13 +325,29 @@ for the call). Infix functions must meet the following requirements: no [default value](#default-arguments). ```kotlin -infix fun Int.shl(x: Int): Int { ... } +//sampleStart +// Defines an infix function that performs string concatenation with a separator +class StringWrapper(val value: String) { + // Joins two strings with the given separator + infix fun joinWith(other: String): String { + return "$value - $other" + } +} + +fun main() { + val greeting = StringWrapper("Hello") -// calling the function using the infix notation -1 shl 2 + // Using infix notation + val result1 = greeting joinWith "World" + println(result1) + // Prints: Hello - World -// is the same as -1.shl(2) + // Using regular method call notation + val result2 = greeting.joinWith("Kotlin") + println(result2) + // Prints: Hello - Kotlin +} +//sampleEnd ``` > Infix function calls have lower precedence than arithmetic operators, type casts, and the `rangeTo` operator. @@ -279,7 +370,7 @@ unambiguous parsing. ```kotlin class MyStringCollection { infix fun add(s: String) { /*...*/ } - + fun build() { this add "abc" // Correct add("abc") // Correct @@ -299,30 +390,48 @@ to top level functions, Kotlin functions can also be declared locally as member Kotlin supports local functions, which are functions inside other functions: ```kotlin -fun dfs(graph: Graph) { - fun dfs(current: Vertex, visited: MutableSet) { - if (!visited.add(current)) return - for (v in current.neighbors) - dfs(v, visited) +//sampleStart +// Calculates the total price with tax and optional discount +fun calculateOrder(items: List, taxRate: Double) { + // Local function to calculate price with tax + fun addTax(price: Double): Double { + return price * (1 + taxRate) } - dfs(graph.vertices[0], HashSet()) -} -``` - -A local function can access local variables of outer functions (the closure). In the case above, `visited` can be a local variable: + // Local function to apply discount if total is over threshold + fun applyDiscount(total: Double): Double { + val discountThreshold = 100.0 + val discountRate = 0.1 + return if (total > discountThreshold) { + total * (1 - discountRate) + } else { + total + } + } -```kotlin -fun dfs(graph: Graph) { - val visited = HashSet() - fun dfs(current: Vertex) { - if (!visited.add(current)) return - for (v in current.neighbors) - dfs(v) + // Calculate total with tax for all items + var total = 0.0 + for (item in items) { + total += addTax(item) } - dfs(graph.vertices[0]) + // Apply discount to final total + val finalTotal = applyDiscount(total) + + println("Subtotal: $${String.format("%.2f", items.sum())}") + println("Total with tax: $${String.format("%.2f", total)}") + println("Final total with discount: $${String.format("%.2f", finalTotal)}") } + +fun main() { + val items = listOf(50.0, 40.0, 20.0) + calculateOrder(items, 0.08) + // Prints: + // Subtotal: $110.00 + // Total with tax: $118.80 + // Final total with discount: $106.92 +} +//sampleEnd ``` ### Member functions @@ -361,27 +470,66 @@ When a function is marked with the `tailrec` modifier and meets the required for the recursion, leaving behind a fast and efficient loop based version instead: ```kotlin -val eps = 1E-10 // "good enough", could be 10^-15 +//sampleStart +// Calculates factorial using tail recursion +tailrec fun factorial(n: Long, accumulator: Long = 1): Long = + when { + n <= 1 -> accumulator + else -> factorial(n - 1, n * accumulator) + } -tailrec fun findFixPoint(x: Double = 1.0): Double = - if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x)) +// Calculates sum of numbers in a range using tail recursion +tailrec fun sumRange(start: Long, end: Long, accumulator: Long = 0): Long = + when { + start > end -> accumulator + else -> sumRange(start + 1, end, accumulator + start) + } + +fun main() { + // Calculate factorial of 5 + val fact5 = factorial(5) + println("Factorial of 5 is: $fact5") + // Prints: Factorial of 5 is: 120 + + // Calculate sum of numbers from 1 to 100 + val sum = sumRange(1, 100) + println("Sum of numbers from 1 to 100 is: $sum") + // Prints: Sum of numbers from 1 to 100 is: 5050 +} +//sampleEnd ``` -This code calculates the `fixpoint` of cosine, which is a mathematical constant. It simply calls `Math.cos` repeatedly -starting at `1.0` until the result no longer changes, yielding a result of `0.7390851332151611` for the specified -`eps` precision. The resulting code is equivalent to this more traditional style: +This code demonstrates two practical uses of tail recursion: +1. Calculating factorial without stack overflow for large numbers +2. Summing a range of numbers efficiently + +The traditional loop-based equivalent would look like this: ```kotlin -val eps = 1E-10 // "good enough", could be 10^-15 - -private fun findFixPoint(): Double { - var x = 1.0 - while (true) { - val y = Math.cos(x) - if (Math.abs(x - y) < eps) return x - x = Math.cos(x) +//sampleStart +// Traditional loop-based factorial calculation +fun factorialLoop(n: Long): Long { + var result = 1L + for (i in 1..n) { + result *= i + } + return result +} + +// Traditional loop-based range sum calculation +fun sumRangeLoop(start: Long, end: Long): Long { + var sum = 0L + for (i in start..end) { + sum += i } + return sum } + +fun main() { + println("Factorial of 5 is: ${factorialLoop(5)}") + println("Sum of 1..100 is: ${sumRangeLoop(1, 100)}") +} +//sampleEnd ``` To be eligible for the `tailrec` modifier, a function must call itself as the last operation it performs. You cannot use @@ -392,4 +540,3 @@ Currently, tail recursion is supported by Kotlin for the JVM and Kotlin/Native. * [Inline functions](inline-functions.md) * [Extension functions](extensions.md) * [Higher-order functions and lambdas](lambdas.md) - From 2a73b3b7013b01e7d1c742beaadedfac1bb4c960 Mon Sep 17 00:00:00 2001 From: "Aleksey.Zamulla" Date: Mon, 17 Feb 2025 14:20:03 +0100 Subject: [PATCH 2/3] fix: better examples, try 2 --- docs/topics/functions.md | 882 ++++++++++++++++++++++++++++----------- 1 file changed, 638 insertions(+), 244 deletions(-) diff --git a/docs/topics/functions.md b/docs/topics/functions.md index 38f461f2e14..6e58fea7bf1 100644 --- a/docs/topics/functions.md +++ b/docs/topics/functions.md @@ -3,59 +3,48 @@ Kotlin functions are declared using the `fun` keyword: ```kotlin +fun main() { //sampleStart -// Doubles the given number +// Defines a function that multiplies its parameter by 2 fun double(number: Int): Int { return 2 * number } -fun main() { - val input = 5 - val result = double(input) - println(result) - // Prints: 10 -} +// Calls the function and stores the result +val result = double(2) +println(result) +// Prints: 4 //sampleEnd +} ``` +{kotlin-runnable="true"} ## Function usage Functions are called using the standard approach: ```kotlin -//sampleStart fun main() { - // Calls the double function with different arguments - val result1 = double(2) - val result2 = double(10) - - println(result1) - // Prints: 4 - println(result2) - // Prints: 20 +//sampleStart +// Defines a simple function +fun double(number: Int): Int { + return 2 * number } + +// Demonstrates function call syntax +val result = double(2) +println(result) +// Prints: 4 //sampleEnd +} ``` +{kotlin-runnable="true"} Calling member functions uses dot notation: ```kotlin -//sampleStart -class TextReader { - // Reads text from a source and returns it as a string - fun readText(): String { - return "Sample text" - } -} - -fun main() { - // Creates an instance of TextReader and calls readText() - val reader = TextReader() - val text = reader.readText() - println(text) - // Prints: Sample text -} -//sampleEnd +// Creates an instance of class Stream and calls its read() method +Stream().read() ``` ### Parameters @@ -64,16 +53,31 @@ Function parameters are defined using Pascal notation - *name*: *type*. Paramete parameter must be explicitly typed: ```kotlin -fun powerOf(number: Int, exponent: Int): Int { /*...*/ } +fun main() { +//sampleStart +// Calculates the power of a number using exponentiation +fun powerOf(number: Int, exponent: Int): Int { + return Math.pow(number.toDouble(), exponent.toDouble()).toInt() +} + +val result = powerOf(2, 3) +println(result) +// Prints: 8 +//sampleEnd +} ``` +{kotlin-runnable="true"} You can use a [trailing comma](coding-conventions.md#trailing-commas) when you declare function parameters: ```kotlin +// Declares a function with parameters using trailing comma fun powerOf( number: Int, exponent: Int, // trailing comma -) { /*...*/ } +) { + println("Calculating $number to the power of $exponent") +} ``` ### Default arguments @@ -82,12 +86,32 @@ Function parameters can have default values, which are used when you skip the co of overloads: ```kotlin -fun read( - b: ByteArray, - off: Int = 0, - len: Int = b.size, -) { /*...*/ } +fun main() { +//sampleStart +// Processes text with customizable options +fun processText( + text: String, + upperCase: Boolean = true, + addPrefix: String = "", +) { + var result = text + if (upperCase) { + result = result.uppercase() + } + println(addPrefix + result) +} + +// Using different combinations of default arguments +processText("hello") +// Prints: HELLO +processText("hello", upperCase = false) +// Prints: hello +processText("hello", addPrefix = "Message: ") +// Prints: Message: HELLO +//sampleEnd +} ``` +{kotlin-runnable="true"} A default value is set by appending `=` to the type. @@ -95,41 +119,101 @@ Overriding methods always use the base method's default parameter values. When overriding a method that has default parameter values, the default parameter values must be omitted from the signature: ```kotlin -open class A { - open fun foo(i: Int = 10) { /*...*/ } +fun main() { +//sampleStart +// Defines a base class with a method having default parameter +open class MessageProcessor { + open fun process(message: String = "Default message") { + println("Processing: $message") + } } -class B : A() { - override fun foo(i: Int) { /*...*/ } // No default value is allowed. +// Creates a derived class that overrides the process method +class CustomProcessor : MessageProcessor() { + override fun process(message: String) { // No default value is allowed + println("Custom processing: $message") + } +} + +// Demonstrates the usage of both classes +val processor = MessageProcessor() +processor.process() // Uses default value +// Prints: Processing: Default message + +val customProcessor = CustomProcessor() +customProcessor.process("Hello") +// Prints: Custom processing: Hello +//sampleEnd } ``` +{kotlin-runnable="true"} If a default parameter precedes a parameter with no default value, the default value can only be used by calling the function with [named arguments](#named-arguments): ```kotlin -fun foo( - bar: Int = 0, - baz: Int, -) { /*...*/ } +fun main() { +//sampleStart +// Configures email settings with default server but required port +fun configureEmail( + server: String = "smtp.default.com", + port: Int, +) { + println("Configuring email: server=$server, port=$port") +} + +// Calls the function using named argument to specify only the required parameter +configureEmail(port = 587) +// Prints: Configuring email: server=smtp.default.com, port=587 -foo(baz = 1) // The default value bar = 0 is used +// Specifies both parameters using named arguments +configureEmail(server = "smtp.custom.com", port = 465) +// Prints: Configuring email: server=smtp.custom.com, port=465 +//sampleEnd +} ``` +{kotlin-runnable="true"} If the last argument after default parameters is a [lambda](lambdas.md#lambda-expression-syntax), you can pass it either as a named argument or [outside the parentheses](lambdas.md#passing-trailing-lambdas): ```kotlin -fun foo( - bar: Int = 0, - baz: Int = 1, - qux: () -> Unit, -) { /*...*/ } - -foo(1) { println("hello") } // Uses the default value baz = 1 -foo(qux = { println("hello") }) // Uses both default values bar = 0 and baz = 1 -foo { println("hello") } // Uses both default values bar = 0 and baz = 1 +fun main() { +//sampleStart +// Processes data with configurable options and a transformation function +fun processData( + data: String, + uppercase: Boolean = false, + transform: () -> String +) { + var result = if (uppercase) data.uppercase() else data + result = transform() + println("Result: $result") +} + +// Passes lambda as the last parameter outside parentheses +processData("hello") { + "Transformed text" +} +// Prints: Result: Transformed text + +// Uses named arguments with lambda +processData( + data = "hello", + uppercase = true, + transform = { "TRANSFORMED TEXT" } +) +// Prints: Result: TRANSFORMED TEXT + +// Uses lambda outside parentheses with default values +processData("hello") { + "Another transformation" +} +// Prints: Result: Another transformation +//sampleEnd +} ``` +{kotlin-runnable="true"} ### Named arguments @@ -139,51 +223,130 @@ arguments and it's difficult to associate a value with an argument, especially i When you use named arguments in a function call, you can freely change the order that they are listed in. If you want to use their default values, you can just leave these arguments out altogether. -Consider the `reformat()` function, which has 4 arguments with default values. +Consider this example of a text formatting function: ```kotlin -fun reformat( - str: String, - normalizeCase: Boolean = true, - upperCaseFirstLetter: Boolean = true, - divideByCamelHumps: Boolean = false, - wordSeparator: Char = ' ', -) { /*...*/ } -``` +fun main() { +//sampleStart +// Formats text with various customization options +fun formatText( + text: String, + capitalizeWords: Boolean = false, + addSpaces: Boolean = true, + removeSpecialChars: Boolean = false, + prefix: String = "", +) { + var result = text + + if (removeSpecialChars) { + result = result.replace(Regex("[^A-Za-z0-9 ]"), "") + } + + if (capitalizeWords) { + result = result.split(" ").map { it.capitalize() }.joinToString(" ") + } -When calling this function, you don't have to name all its arguments: + if (!addSpaces) { + result = result.replace(" ", "") + } -```kotlin -reformat( - "String!", - false, - upperCaseFirstLetter = false, - divideByCamelHumps = true, - '_' + println(prefix + result) +} + +// Calls function without named arguments - harder to understand the purpose of each boolean +formatText("hello world!", true, false, true) +// Prints: Hello World + +// Calls function with named arguments - much clearer what each parameter does +formatText( + text = "hello world!", + capitalizeWords = true, + addSpaces = false, + removeSpecialChars = true +) +// Prints: HelloWorld + +// Uses named arguments to skip some parameters with default values +formatText( + text = "hello world!", + capitalizeWords = true, + prefix = "Result: " ) +// Prints: Result: Hello World +//sampleEnd +} ``` +{kotlin-runnable="true"} -You can skip all the ones with default values: +After the first skipped argument, you must name all subsequent arguments. This helps maintain code clarity: ```kotlin -reformat("This is a long String!") -``` +fun main() { +//sampleStart +// Formats user data with various options +fun formatUserData( + name: String, + age: Int, + isAdmin: Boolean = false, + showEmail: Boolean = true, + email: String = "" +) { + println("User: $name, Age: $age" + + (if (isAdmin) " (Admin)" else "") + + (if (showEmail && email.isNotEmpty()) ", Email: $email" else "")) +} -You are also able to skip specific arguments with default values, rather than omitting them all. However, after the first -skipped argument, you must name all subsequent arguments: +// Uses mix of positional and named arguments +formatUserData("Alice", 25, showEmail = true, email = "alice@example.com") +// Prints: User: Alice, Age: 25, Email: alice@example.com -```kotlin -reformat("This is a short String!", upperCaseFirstLetter = false, wordSeparator = '_') +// Uses all named arguments in different order +formatUserData( + age = 30, + name = "Bob", + isAdmin = true, + email = "bob@example.com" +) +// Prints: User: Bob, Age: 30 (Admin), Email: bob@example.com +//sampleEnd +} ``` +{kotlin-runnable="true"} You can pass a [variable number of arguments (`vararg`)](#variable-number-of-arguments-varargs) with names using the `spread` operator: ```kotlin -fun foo(vararg strings: String) { /*...*/ } +fun main() { +//sampleStart +// Processes multiple log messages with a specified log level +fun logMessages(level: String = "INFO", vararg messages: String) { + messages.forEach { message -> + println("[$level] $message") + } +} -foo(strings = *arrayOf("a", "b", "c")) +// Creates an array of messages +val debugMessages = arrayOf("Starting process", "Process completed") + +// Uses named arguments with spread operator +logMessages( + level = "DEBUG", + messages = *debugMessages +) +// Prints: +// [DEBUG] Starting process +// [DEBUG] Process completed + +// Passes individual messages directly +logMessages("WARNING", "Invalid input", "Process failed") +// Prints: +// [WARNING] Invalid input +// [WARNING] Process failed +//sampleEnd +} ``` +{kotlin-runnable="true"} > When calling Java functions on the JVM, you can't use the named argument syntax because Java bytecode does not > always preserve the names of function parameters. @@ -196,56 +359,129 @@ If a function does not return a useful value, its return type is `Unit`. `Unit` This value does not have to be returned explicitly: ```kotlin -fun printHello(name: String?): Unit { - if (name != null) - println("Hello $name") - else - println("Hi there!") - // `return Unit` or `return` is optional +fun main() { +//sampleStart +// Demonstrates a Unit-returning function with explicit return type +fun greetUser(name: String?): Unit { + if (name != null) { + println("Hello, $name!") + } else { + println("Hello, guest!") + } + // No explicit return needed +} + +// Calls the function with different arguments +greetUser("Alice") +// Prints: Hello, Alice! +greetUser(null) +// Prints: Hello, guest! +//sampleEnd } ``` +{kotlin-runnable="true"} The `Unit` return type declaration is also optional. The above code is equivalent to: ```kotlin +fun main() { //sampleStart -// Prints a greeting message based on the provided name -fun printHello(name: String?) { - if (name != null) - println("Hello $name") - else - println("Hi there!") +// Demonstrates a Unit-returning function without explicit return type +fun greetUser(name: String?) { + if (name != null) { + println("Hello, $name!") + } else { + println("Hello, guest!") + } } -fun main() { - printHello("Alice") - // Prints: Hello Alice - - printHello(null) - // Prints: Hi there! -} +// Function behaves the same way +greetUser("Bob") +// Prints: Hello, Bob! //sampleEnd +} ``` +{kotlin-runnable="true"} ### Single-expression functions When the function body consists of a single expression, the curly braces can be omitted and the body specified after an `=` symbol: ```kotlin -fun double(x: Int): Int = x * 2 +fun main() { +//sampleStart +// Demonstrates a single-expression function with explicit return type +fun calculateArea(width: Int, height: Int): Int = width * height + +// Uses the function to calculate rectangle areas +val smallRectangle = calculateArea(2, 3) +println("Small rectangle area: $smallRectangle") +// Prints: Small rectangle area: 6 + +val largeRectangle = calculateArea(10, 20) +println("Large rectangle area: $largeRectangle") +// Prints: Large rectangle area: 200 +//sampleEnd +} ``` +{kotlin-runnable="true"} Explicitly declaring the return type is [optional](#explicit-return-types) when this can be inferred by the compiler: ```kotlin -fun double(x: Int) = x * 2 +fun main() { +//sampleStart +// Demonstrates a single-expression function with type inference +fun calculateCircleArea(radius: Double) = Math.PI * radius * radius + +// Uses the function with different radius values +val smallCircle = calculateCircleArea(2.0) +println("Small circle area: %.2f".format(smallCircle)) +// Prints: Small circle area: 12.57 + +val largeCircle = calculateCircleArea(5.0) +println("Large circle area: %.2f".format(largeCircle)) +// Prints: Large circle area: 78.54 +//sampleEnd +} ``` +{kotlin-runnable="true"} ### Explicit return types Functions with block body must always specify return types explicitly, unless it's intended for them to return `Unit`, [in which case specifying the return type is optional](#unit-returning-functions). +```kotlin +fun main() { +//sampleStart +// Demonstrates a function requiring explicit return type due to complex logic +fun calculateGrade(score: Int): String { + if (score < 0 || score > 100) { + return "Invalid Score" + } + + return when { + score >= 90 -> "A" + score >= 80 -> "B" + score >= 70 -> "C" + score >= 60 -> "D" + else -> "F" + } +} + +// Tests the function with different scores +println("Score 95: ${calculateGrade(95)}") +// Prints: Score 95: A +println("Score 85: ${calculateGrade(85)}") +// Prints: Score 85: B +println("Score -5: ${calculateGrade(-5)}") +// Prints: Score -5: Invalid Score +//sampleEnd +} +``` +{kotlin-runnable="true"} + Kotlin does not infer return types for functions with block bodies because such functions may have complex control flow in the body, and the return type will be non-obvious to the reader (and sometimes even for the compiler). @@ -254,101 +490,140 @@ in the body, and the return type will be non-obvious to the reader (and sometime You can mark a parameter of a function (usually the last one) with the `vararg` modifier: ```kotlin +fun main() { //sampleStart // Creates a list from a variable number of elements fun createList(vararg elements: T): List { - val resultList = ArrayList() - // Iterates through the elements array and adds each to the list - for (element in elements) { - resultList.add(element) - } - return resultList + // Converts vararg parameter to list + return elements.toList() } -fun main() { - // Creates lists with different numbers of elements - val numbers = createList(1, 2, 3, 4, 5) - println(numbers) - // Prints: [1, 2, 3, 4, 5] +// Demonstrates different ways to use vararg parameter +val numbers = createList(1, 2, 3, 4, 5) +println("Numbers: $numbers") +// Prints: Numbers: [1, 2, 3, 4, 5] - val fruits = createList("apple", "banana", "orange") - println(fruits) - // Prints: [apple, banana, orange] -} +val fruits = createList("apple", "banana", "orange") +println("Fruits: $fruits") +// Prints: Fruits: [apple, banana, orange] //sampleEnd +} ``` +{kotlin-runnable="true"} -In this case, you can pass a variable number of arguments to the function: +Inside a function, a `vararg`-parameter of type `T` is visible as an array of `T`. Only one parameter can be marked as `vararg`. +If a `vararg` parameter is not the last one in the list, values for the subsequent parameters must be passed using named arguments. -```kotlin -val list = asList(1, 2, 3) -``` +Here's an example demonstrating more complex usage of varargs: -Inside a function, a `vararg`-parameter of type `T` is visible as an array of `T`, as in the example above, where the `ts` -variable has type `Array`. +```kotlin +fun main() { +//sampleStart +// Processes multiple items with a prefix +fun processItems(prefix: String, vararg items: String) { + items.forEach { item -> + println("$prefix: $item") + } +} -Only one parameter can be marked as `vararg`. If a `vararg` parameter is not the last one in the list, values for the -subsequent parameters can be passed using named argument syntax, or, if the parameter has a function type, by passing -a lambda outside the parentheses. +// Uses vararg with individual arguments +processItems("Item", "A", "B", "C") +// Prints: +// Item: A +// Item: B +// Item: C + +// Uses spread operator with an array +val moreItems = arrayOf("X", "Y", "Z") +processItems("Element", *moreItems) +// Prints: +// Element: X +// Element: Y +// Element: Z +//sampleEnd +} +``` +{kotlin-runnable="true"} -When you call a `vararg`-function, you can pass arguments individually, for example `asList(1, 2, 3)`. If you already have -an array and want to pass its contents to the function, use the *spread* operator (prefix the array with `*`): +When working with primitive type arrays, you need to convert them to regular arrays: ```kotlin -//sampleStart fun main() { - // Creates a regular array of strings - val colors = arrayOf("red", "green", "blue") - // Creates a list with additional elements before and after the array - val colorList = createList("purple", "yellow", *colors, "orange") - println(colorList) - // Prints: [purple, yellow, red, green, blue, orange] - - // Creates a primitive type array of integers - val numbers = intArrayOf(1, 2, 3) - // Converts primitive array to regular array and creates a list - val numberList = createList(0, *numbers.toTypedArray(), 4, 5) - println(numberList) - // Prints: [0, 1, 2, 3, 4, 5] +//sampleStart +// Demonstrates working with primitive arrays and varargs +fun sumNumbers(vararg numbers: Int): Int { + return numbers.sum() } + +// Creates a primitive type array +val primitiveArray = intArrayOf(1, 2, 3) + +// Converts primitive array to regular array and uses spread operator +val sum = sumNumbers(*primitiveArray) +println("Sum: $sum") +// Prints: Sum: 6 //sampleEnd +} ``` +{kotlin-runnable="true"} ### Infix notation Functions marked with the `infix` keyword can also be called using the infix notation (omitting the dot and the parentheses for the call). Infix functions must meet the following requirements: -* They must be member functions or [extension functions](extensions.md). -* They must have a single parameter. +* They must be member functions or [extension functions](extensions.md) +* They must have a single parameter * The parameter must not [accept variable number of arguments](#variable-number-of-arguments-varargs) and must have -no [default value](#default-arguments). +no [default value](#default-arguments) ```kotlin +fun main() { //sampleStart -// Defines an infix function that performs string concatenation with a separator -class StringWrapper(val value: String) { - // Joins two strings with the given separator - infix fun joinWith(other: String): String { - return "$value - $other" +// Defines a class with an infix function +class PairNumber(val value: Int) { + // Creates an infix function to pair numbers + infix fun pair(other: Int): Pair { + return Pair(this.value, other) } } -fun main() { - val greeting = StringWrapper("Hello") +// Uses the infix function notation +val number = PairNumber(1) +val pair1 = number pair 2 // Infix notation +val pair2 = number.pair(3) // Standard notation + +println("Infix notation result: $pair1") +// Prints: Infix notation result: (1, 2) +println("Standard notation result: $pair2") +// Prints: Standard notation result: (1, 3) +//sampleEnd +} +``` +{kotlin-runnable="true"} - // Using infix notation - val result1 = greeting joinWith "World" - println(result1) - // Prints: Hello - World +Here's another example with a custom string operation: - // Using regular method call notation - val result2 = greeting.joinWith("Kotlin") - println(result2) - // Prints: Hello - Kotlin +```kotlin +fun main() { +//sampleStart +// Defines an infix extension function for String +infix fun String.addSeparator(other: String): String { + return "$this -> $other" } + +// Uses the infix function in different ways +val result1 = "Hello" addSeparator "World" // Infix notation +val result2 = "Kotlin".addSeparator("Fun") // Standard notation + +println(result1) +// Prints: Hello -> World +println(result2) +// Prints: Kotlin -> Fun //sampleEnd +} ``` +{kotlin-runnable="true"} > Infix function calls have lower precedence than arithmetic operators, type casts, and the `rangeTo` operator. > The following expressions are equivalent: @@ -364,20 +639,38 @@ fun main() { {style="note"} Note that infix functions always require both the receiver and the parameter to be specified. When you're -calling a method on the current receiver using the infix notation, use `this` explicitly. This is required to ensure -unambiguous parsing. +calling a method on the current receiver using the infix notation, use `this` explicitly: ```kotlin -class MyStringCollection { - infix fun add(s: String) { /*...*/ } +fun main() { +//sampleStart +// Defines a collection class with an infix function +class StringCollection { + private val items = mutableListOf() - fun build() { - this add "abc" // Correct - add("abc") // Correct - //add "abc" // Incorrect: the receiver must be specified + // Defines an infix function to add items + infix fun add(item: String) { + items.add(item) } + + // Demonstrates different ways to call the add function + fun addItems() { + this add "First" // Correct: uses infix notation with explicit receiver + add("Second") // Correct: uses standard notation + // add "Third" // Incorrect: receiver must be specified for infix notation + + println("Items in collection: $items") + } +} + +// Creates an instance and adds items +val collection = StringCollection() +collection.addItems() +// Prints: Items in collection: [First, Second] +//sampleEnd } ``` +{kotlin-runnable="true"} ## Function scope @@ -385,70 +678,148 @@ Kotlin functions can be declared at the top level in a file, meaning you do not which you are required to do in languages such as Java, C#, and Scala ([top level definition is available since Scala 3](https://docs.scala-lang.org/scala3/book/taste-toplevel-definitions.html#inner-main)). In addition to top level functions, Kotlin functions can also be declared locally as member functions and extension functions. -### Local functions - -Kotlin supports local functions, which are functions inside other functions: +Here's an example demonstrating different function scopes: ```kotlin +fun main() { //sampleStart -// Calculates the total price with tax and optional discount -fun calculateOrder(items: List, taxRate: Double) { - // Local function to calculate price with tax - fun addTax(price: Double): Double { - return price * (1 + taxRate) +// Top-level function (imagine this at file level) +fun calculateSquare(number: Int): Int { + return number * number +} + +// Class with member function +class Calculator { + private var result: Int = 0 + + // Member function + fun add(number: Int) { + result += number + println("Current result: $result") } - // Local function to apply discount if total is over threshold - fun applyDiscount(total: Double): Double { - val discountThreshold = 100.0 - val discountRate = 0.1 - return if (total > discountThreshold) { - total * (1 - discountRate) - } else { - total + // Function with local function + fun calculateSumOfSquares(vararg numbers: Int) { + // Local function that can access outer scope + fun square(n: Int) = n * n + + var sum = 0 + for (number in numbers) { + sum += square(number) // Uses local function } + println("Sum of squares: $sum") } +} - // Calculate total with tax for all items - var total = 0.0 - for (item in items) { - total += addTax(item) - } +// Demonstrates usage of functions in different scopes +val square = calculateSquare(5) +println("Square of 5: $square") +// Prints: Square of 5: 25 - // Apply discount to final total - val finalTotal = applyDiscount(total) +val calculator = Calculator() +calculator.add(3) +// Prints: Current result: 3 +calculator.add(7) +// Prints: Current result: 10 - println("Subtotal: $${String.format("%.2f", items.sum())}") - println("Total with tax: $${String.format("%.2f", total)}") - println("Final total with discount: $${String.format("%.2f", finalTotal)}") +calculator.calculateSumOfSquares(2, 3, 4) +// Prints: Sum of squares: 29 +//sampleEnd } +``` +{kotlin-runnable="true"} + +### Local functions +Kotlin supports local functions, which are functions inside other functions. Local functions can access variables from the outer scope: + +```kotlin fun main() { - val items = listOf(50.0, 40.0, 20.0) - calculateOrder(items, 0.08) - // Prints: - // Subtotal: $110.00 - // Total with tax: $118.80 - // Final total with discount: $106.92 +//sampleStart +// Demonstrates local functions with access to outer scope +fun processNumbers(numbers: List) { + var count = 0 + + // Local function that can access count from outer scope + fun incrementCountFor(predicate: (Int) -> Boolean) { + for (number in numbers) { + if (predicate(number)) { + count++ + } + } + println("Found $count numbers") + } + + // Uses local function to count even numbers + incrementCountFor { it % 2 == 0 } + // Prints: Found {number of even integers} numbers + + count = 0 // Resets counter + + // Uses local function to count numbers greater than 5 + incrementCountFor { it > 5 } + // Prints: Found {number of integers > 5} numbers } + +// Tests the function with a list of numbers +processNumbers(listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) //sampleEnd +} ``` +{kotlin-runnable="true"} ### Member functions A member function is a function that is defined inside a class or object: ```kotlin -class Sample { - fun foo() { print("Foo") } +fun main() { +//sampleStart +// Defines a class representing a bank account +class BankAccount(private var balance: Double) { + // Member function to deposit money + fun deposit(amount: Double) { + if (amount > 0) { + balance += amount + println("Deposited $amount. New balance: $balance") + } else { + println("Invalid deposit amount") + } + } + + // Member function to withdraw money + fun withdraw(amount: Double) { + if (amount > 0 && amount <= balance) { + balance -= amount + println("Withdrawn $amount. New balance: $balance") + } else { + println("Invalid withdrawal amount or insufficient funds") + } + } + + // Member function to check balance + fun checkBalance() { + println("Current balance: $balance") + } } -``` -Member functions are called with dot notation: +// Creates an account and performs operations +val account = BankAccount(100.0) +account.checkBalance() +// Prints: Current balance: 100.0 -```kotlin -Sample().foo() // creates instance of class Sample and calls foo +account.deposit(50.0) +// Prints: Deposited 50.0. New balance: 150.0 + +account.withdraw(70.0) +// Prints: Withdrawn 70.0. New balance: 80.0 + +account.withdraw(100.0) +// Prints: Invalid withdrawal amount or insufficient funds +//sampleEnd +} ``` +{kotlin-runnable="true"} For more information on classes and overriding members see [Classes](classes.md) and [Inheritance](classes.md#inheritance). @@ -457,8 +828,30 @@ For more information on classes and overriding members see [Classes](classes.md) Functions can have generic parameters, which are specified using angle brackets before the function name: ```kotlin -fun singletonList(item: T): List { /*...*/ } +fun main() { +//sampleStart +// Demonstrates a generic function that creates a list wrapper +class ListWrapper(private val item: T) { + fun getList(): List = listOf(item) +} + +// Generic function to create a ListWrapper +fun wrapInList(item: T): ListWrapper { + return ListWrapper(item) +} + +// Uses the generic function with different types +val numberWrapper = wrapInList(42) +println("Number list: ${numberWrapper.getList()}") +// Prints: Number list: [42] + +val stringWrapper = wrapInList("Hello") +println("String list: ${stringWrapper.getList()}") +// Prints: String list: [Hello] +//sampleEnd +} ``` +{kotlin-runnable="true"} For more information on generic functions, see [Generics](generics.md). @@ -470,6 +863,7 @@ When a function is marked with the `tailrec` modifier and meets the required for the recursion, leaving behind a fast and efficient loop based version instead: ```kotlin +fun main() { //sampleStart // Calculates factorial using tail recursion tailrec fun factorial(n: Long, accumulator: Long = 1): Long = @@ -478,36 +872,41 @@ tailrec fun factorial(n: Long, accumulator: Long = 1): Long = else -> factorial(n - 1, n * accumulator) } -// Calculates sum of numbers in a range using tail recursion -tailrec fun sumRange(start: Long, end: Long, accumulator: Long = 0): Long = - when { - start > end -> accumulator - else -> sumRange(start + 1, end, accumulator + start) - } +// Tests factorial function with different numbers +println("Factorial of 5: ${factorial(5)}") +// Prints: Factorial of 5: 120 -fun main() { - // Calculate factorial of 5 - val fact5 = factorial(5) - println("Factorial of 5 is: $fact5") - // Prints: Factorial of 5 is: 120 +println("Factorial of 10: ${factorial(10)}") +// Prints: Factorial of 10: 3628800 - // Calculate sum of numbers from 1 to 100 - val sum = sumRange(1, 100) - println("Sum of numbers from 1 to 100 is: $sum") - // Prints: Sum of numbers from 1 to 100 is: 5050 -} +// Demonstrates a more complex tail recursive function +// Finds the greatest common divisor using Euclidean algorithm +tailrec fun gcd(a: Int, b: Int): Int = + if (b == 0) a + else gcd(b, a % b) + +// Tests GCD function with different number pairs +println("GCD of 48 and 36: ${gcd(48, 36)}") +// Prints: GCD of 48 and 36: 12 + +println("GCD of 125 and 25: ${gcd(125, 25)}") +// Prints: GCD of 125 and 25: 25 //sampleEnd +} ``` +{kotlin-runnable="true"} -This code demonstrates two practical uses of tail recursion: -1. Calculating factorial without stack overflow for large numbers -2. Summing a range of numbers efficiently - -The traditional loop-based equivalent would look like this: +The equivalent non-tail-recursive implementation would look like this: ```kotlin +fun main() { //sampleStart -// Traditional loop-based factorial calculation +// Non-tail-recursive factorial (less efficient, risk of stack overflow) +fun factorial(n: Long): Long = + if (n <= 1) 1 + else n * factorial(n - 1) // Not tail recursive: multiplication after recursive call + +// Traditional loop-based implementation fun factorialLoop(n: Long): Long { var result = 1L for (i in 1..n) { @@ -516,21 +915,16 @@ fun factorialLoop(n: Long): Long { return result } -// Traditional loop-based range sum calculation -fun sumRangeLoop(start: Long, end: Long): Long { - var sum = 0L - for (i in start..end) { - sum += i - } - return sum -} - -fun main() { - println("Factorial of 5 is: ${factorialLoop(5)}") - println("Sum of 1..100 is: ${sumRangeLoop(1, 100)}") -} +// Compares results of different implementations +val n = 5L +println("Tail recursive factorial: ${factorial(n, 1)}") +println("Non-tail recursive factorial: ${factorial(n)}") +println("Loop-based factorial: ${factorialLoop(n)}") +// All print: 120 //sampleEnd +} ``` +{kotlin-runnable="true"} To be eligible for the `tailrec` modifier, a function must call itself as the last operation it performs. You cannot use tail recursion when there is more code after the recursive call, within `try`/`catch`/`finally` blocks, or on open functions. From 638a2c26ef16eb89eb1d79f1f65cfcdbd34512a1 Mon Sep 17 00:00:00 2001 From: "Aleksey.Zamulla" Date: Fri, 21 Feb 2025 12:05:54 +0100 Subject: [PATCH 3/3] fix: * correct indentations in functions.md * add (not always fitting, but correct) print comments to generics.md, idioms.md, and interfaces.md --- docs/topics/functions.md | 1056 ++++++++++++++++++------------------- docs/topics/generics.md | 5 + docs/topics/idioms.md | 9 +- docs/topics/interfaces.md | 7 +- 4 files changed, 545 insertions(+), 532 deletions(-) diff --git a/docs/topics/functions.md b/docs/topics/functions.md index 6e58fea7bf1..a1899b42f3f 100644 --- a/docs/topics/functions.md +++ b/docs/topics/functions.md @@ -4,17 +4,17 @@ Kotlin functions are declared using the `fun` keyword: ```kotlin fun main() { -//sampleStart -// Defines a function that multiplies its parameter by 2 -fun double(number: Int): Int { - return 2 * number -} + //sampleStart + // Defines a function that multiplies its parameter by 2 + fun double(number: Int): Int { + return 2 * number + } -// Calls the function and stores the result -val result = double(2) -println(result) -// Prints: 4 -//sampleEnd + // Calls the function and stores the result + val result = double(2) + println(result) + // Prints: 4 + //sampleEnd } ``` {kotlin-runnable="true"} @@ -25,17 +25,17 @@ Functions are called using the standard approach: ```kotlin fun main() { -//sampleStart -// Defines a simple function -fun double(number: Int): Int { - return 2 * number -} + //sampleStart + // Defines a simple function + fun double(number: Int): Int { + return 2 * number + } -// Demonstrates function call syntax -val result = double(2) -println(result) -// Prints: 4 -//sampleEnd + // Demonstrates function call syntax + val result = double(2) + println(result) + // Prints: 4 + //sampleEnd } ``` {kotlin-runnable="true"} @@ -54,16 +54,16 @@ parameter must be explicitly typed: ```kotlin fun main() { -//sampleStart -// Calculates the power of a number using exponentiation -fun powerOf(number: Int, exponent: Int): Int { - return Math.pow(number.toDouble(), exponent.toDouble()).toInt() -} + //sampleStart + // Calculates the power of a number using exponentiation + fun powerOf(number: Int, exponent: Int): Int { + return Math.pow(number.toDouble(), exponent.toDouble()).toInt() + } -val result = powerOf(2, 3) -println(result) -// Prints: 8 -//sampleEnd + val result = powerOf(2, 3) + println(result) + // Prints: 8 + //sampleEnd } ``` {kotlin-runnable="true"} @@ -87,28 +87,28 @@ of overloads: ```kotlin fun main() { -//sampleStart -// Processes text with customizable options -fun processText( - text: String, - upperCase: Boolean = true, - addPrefix: String = "", -) { - var result = text - if (upperCase) { - result = result.uppercase() + //sampleStart + // Processes text with customizable options + fun processText( + text: String, + upperCase: Boolean = true, + addPrefix: String = "", + ) { + var result = text + if (upperCase) { + result = result.uppercase() + } + println(addPrefix + result) } - println(addPrefix + result) -} -// Using different combinations of default arguments -processText("hello") -// Prints: HELLO -processText("hello", upperCase = false) -// Prints: hello -processText("hello", addPrefix = "Message: ") -// Prints: Message: HELLO -//sampleEnd + // Using different combinations of default arguments + processText("hello") + // Prints: HELLO + processText("hello", upperCase = false) + // Prints: hello + processText("hello", addPrefix = "Message: ") + // Prints: Message: HELLO + //sampleEnd } ``` {kotlin-runnable="true"} @@ -120,30 +120,30 @@ When overriding a method that has default parameter values, the default paramete ```kotlin fun main() { -//sampleStart -// Defines a base class with a method having default parameter -open class MessageProcessor { - open fun process(message: String = "Default message") { - println("Processing: $message") + //sampleStart + // Defines a base class with a method having default parameter + open class MessageProcessor { + open fun process(message: String = "Default message") { + println("Processing: $message") + } } -} -// Creates a derived class that overrides the process method -class CustomProcessor : MessageProcessor() { - override fun process(message: String) { // No default value is allowed - println("Custom processing: $message") + // Creates a derived class that overrides the process method + class CustomProcessor : MessageProcessor() { + override fun process(message: String) { // No default value is allowed + println("Custom processing: $message") + } } -} -// Demonstrates the usage of both classes -val processor = MessageProcessor() -processor.process() // Uses default value -// Prints: Processing: Default message + // Demonstrates the usage of both classes + val processor = MessageProcessor() + processor.process() // Uses default value + // Prints: Processing: Default message -val customProcessor = CustomProcessor() -customProcessor.process("Hello") -// Prints: Custom processing: Hello -//sampleEnd + val customProcessor = CustomProcessor() + customProcessor.process("Hello") + // Prints: Custom processing: Hello + //sampleEnd } ``` {kotlin-runnable="true"} @@ -153,23 +153,23 @@ the function with [named arguments](#named-arguments): ```kotlin fun main() { -//sampleStart -// Configures email settings with default server but required port -fun configureEmail( - server: String = "smtp.default.com", - port: Int, -) { - println("Configuring email: server=$server, port=$port") -} + //sampleStart + // Configures email settings with default server but required port + fun configureEmail( + server: String = "smtp.default.com", + port: Int, + ) { + println("Configuring email: server=$server, port=$port") + } -// Calls the function using named argument to specify only the required parameter -configureEmail(port = 587) -// Prints: Configuring email: server=smtp.default.com, port=587 + // Calls the function using named argument to specify only the required parameter + configureEmail(port = 587) + // Prints: Configuring email: server=smtp.default.com, port=587 -// Specifies both parameters using named arguments -configureEmail(server = "smtp.custom.com", port = 465) -// Prints: Configuring email: server=smtp.custom.com, port=465 -//sampleEnd + // Specifies both parameters using named arguments + configureEmail(server = "smtp.custom.com", port = 465) + // Prints: Configuring email: server=smtp.custom.com, port=465 + //sampleEnd } ``` {kotlin-runnable="true"} @@ -179,38 +179,38 @@ you can pass it either as a named argument or [outside the parentheses](lambdas. ```kotlin fun main() { -//sampleStart -// Processes data with configurable options and a transformation function -fun processData( - data: String, - uppercase: Boolean = false, - transform: () -> String -) { - var result = if (uppercase) data.uppercase() else data - result = transform() - println("Result: $result") -} + //sampleStart + // Processes data with configurable options and a transformation function + fun processData( + data: String, + uppercase: Boolean = false, + transform: () -> String + ) { + var result = if (uppercase) data.uppercase() else data + result = transform() + println("Result: $result") + } -// Passes lambda as the last parameter outside parentheses -processData("hello") { - "Transformed text" -} -// Prints: Result: Transformed text - -// Uses named arguments with lambda -processData( - data = "hello", - uppercase = true, - transform = { "TRANSFORMED TEXT" } -) -// Prints: Result: TRANSFORMED TEXT - -// Uses lambda outside parentheses with default values -processData("hello") { - "Another transformation" -} -// Prints: Result: Another transformation -//sampleEnd + // Passes lambda as the last parameter outside parentheses + processData("hello") { + "Transformed text" + } + // Prints: Result: Transformed text + + // Uses named arguments with lambda + processData( + data = "hello", + uppercase = true, + transform = { "TRANSFORMED TEXT" } + ) + // Prints: Result: TRANSFORMED TEXT + + // Uses lambda outside parentheses with default values + processData("hello") { + "Another transformation" + } + // Prints: Result: Another transformation + //sampleEnd } ``` {kotlin-runnable="true"} @@ -227,53 +227,53 @@ Consider this example of a text formatting function: ```kotlin fun main() { -//sampleStart -// Formats text with various customization options -fun formatText( - text: String, - capitalizeWords: Boolean = false, - addSpaces: Boolean = true, - removeSpecialChars: Boolean = false, - prefix: String = "", -) { - var result = text + //sampleStart + // Formats text with various customization options + fun formatText( + text: String, + capitalizeWords: Boolean = false, + addSpaces: Boolean = true, + removeSpecialChars: Boolean = false, + prefix: String = "", + ) { + var result = text + + if (removeSpecialChars) { + result = result.replace(Regex("[^A-Za-z0-9 ]"), "") + } - if (removeSpecialChars) { - result = result.replace(Regex("[^A-Za-z0-9 ]"), "") - } + if (capitalizeWords) { + result = result.split(" ").map { it.capitalize() }.joinToString(" ") + } - if (capitalizeWords) { - result = result.split(" ").map { it.capitalize() }.joinToString(" ") - } + if (!addSpaces) { + result = result.replace(" ", "") + } - if (!addSpaces) { - result = result.replace(" ", "") + println(prefix + result) } - println(prefix + result) -} - -// Calls function without named arguments - harder to understand the purpose of each boolean -formatText("hello world!", true, false, true) -// Prints: Hello World - -// Calls function with named arguments - much clearer what each parameter does -formatText( - text = "hello world!", - capitalizeWords = true, - addSpaces = false, - removeSpecialChars = true -) -// Prints: HelloWorld - -// Uses named arguments to skip some parameters with default values -formatText( - text = "hello world!", - capitalizeWords = true, - prefix = "Result: " -) -// Prints: Result: Hello World -//sampleEnd + // Calls function without named arguments - harder to understand the purpose of each boolean + formatText("hello world!", true, false, true) + // Prints: Hello World + + // Calls function with named arguments - much clearer what each parameter does + formatText( + text = "hello world!", + capitalizeWords = true, + addSpaces = false, + removeSpecialChars = true + ) + // Prints: HelloWorld + + // Uses named arguments to skip some parameters with default values + formatText( + text = "hello world!", + capitalizeWords = true, + prefix = "Result: " + ) + // Prints: Result: Hello World + //sampleEnd } ``` {kotlin-runnable="true"} @@ -282,33 +282,33 @@ After the first skipped argument, you must name all subsequent arguments. This h ```kotlin fun main() { -//sampleStart -// Formats user data with various options -fun formatUserData( - name: String, - age: Int, - isAdmin: Boolean = false, - showEmail: Boolean = true, - email: String = "" -) { - println("User: $name, Age: $age" + - (if (isAdmin) " (Admin)" else "") + - (if (showEmail && email.isNotEmpty()) ", Email: $email" else "")) -} + //sampleStart + // Formats user data with various options + fun formatUserData( + name: String, + age: Int, + isAdmin: Boolean = false, + showEmail: Boolean = true, + email: String = "" + ) { + println("User: $name, Age: $age" + + (if (isAdmin) " (Admin)" else "") + + (if (showEmail && email.isNotEmpty()) ", Email: $email" else "")) + } -// Uses mix of positional and named arguments -formatUserData("Alice", 25, showEmail = true, email = "alice@example.com") -// Prints: User: Alice, Age: 25, Email: alice@example.com - -// Uses all named arguments in different order -formatUserData( - age = 30, - name = "Bob", - isAdmin = true, - email = "bob@example.com" -) -// Prints: User: Bob, Age: 30 (Admin), Email: bob@example.com -//sampleEnd + // Uses mix of positional and named arguments + formatUserData("Alice", 25, showEmail = true, email = "alice@example.com") + // Prints: User: Alice, Age: 25, Email: alice@example.com + + // Uses all named arguments in different order + formatUserData( + age = 30, + name = "Bob", + isAdmin = true, + email = "bob@example.com" + ) + // Prints: User: Bob, Age: 30 (Admin), Email: bob@example.com + //sampleEnd } ``` {kotlin-runnable="true"} @@ -318,32 +318,32 @@ You can pass a [variable number of arguments (`vararg`)](#variable-number-of-arg ```kotlin fun main() { -//sampleStart -// Processes multiple log messages with a specified log level -fun logMessages(level: String = "INFO", vararg messages: String) { - messages.forEach { message -> - println("[$level] $message") + //sampleStart + // Processes multiple log messages with a specified log level + fun logMessages(level: String = "INFO", vararg messages: String) { + messages.forEach { message -> + println("[$level] $message") + } } -} -// Creates an array of messages -val debugMessages = arrayOf("Starting process", "Process completed") - -// Uses named arguments with spread operator -logMessages( - level = "DEBUG", - messages = *debugMessages -) -// Prints: -// [DEBUG] Starting process -// [DEBUG] Process completed - -// Passes individual messages directly -logMessages("WARNING", "Invalid input", "Process failed") -// Prints: -// [WARNING] Invalid input -// [WARNING] Process failed -//sampleEnd + // Creates an array of messages + val debugMessages = arrayOf("Starting process", "Process completed") + + // Uses named arguments with spread operator + logMessages( + level = "DEBUG", + messages = *debugMessages + ) + // Prints: + // [DEBUG] Starting process + // [DEBUG] Process completed + + // Passes individual messages directly + logMessages("WARNING", "Invalid input", "Process failed") + // Prints: + // [WARNING] Invalid input + // [WARNING] Process failed + //sampleEnd } ``` {kotlin-runnable="true"} @@ -360,23 +360,23 @@ This value does not have to be returned explicitly: ```kotlin fun main() { -//sampleStart -// Demonstrates a Unit-returning function with explicit return type -fun greetUser(name: String?): Unit { - if (name != null) { - println("Hello, $name!") - } else { - println("Hello, guest!") + //sampleStart + // Demonstrates a Unit-returning function with explicit return type + fun greetUser(name: String?): Unit { + if (name != null) { + println("Hello, $name!") + } else { + println("Hello, guest!") + } + // No explicit return needed } - // No explicit return needed -} -// Calls the function with different arguments -greetUser("Alice") -// Prints: Hello, Alice! -greetUser(null) -// Prints: Hello, guest! -//sampleEnd + // Calls the function with different arguments + greetUser("Alice") + // Prints: Hello, Alice! + greetUser(null) + // Prints: Hello, guest! + //sampleEnd } ``` {kotlin-runnable="true"} @@ -385,20 +385,20 @@ The `Unit` return type declaration is also optional. The above code is equivalen ```kotlin fun main() { -//sampleStart -// Demonstrates a Unit-returning function without explicit return type -fun greetUser(name: String?) { - if (name != null) { - println("Hello, $name!") - } else { - println("Hello, guest!") + //sampleStart + // Demonstrates a Unit-returning function without explicit return type + fun greetUser(name: String?) { + if (name != null) { + println("Hello, $name!") + } else { + println("Hello, guest!") + } } -} -// Function behaves the same way -greetUser("Bob") -// Prints: Hello, Bob! -//sampleEnd + // Function behaves the same way + greetUser("Bob") + // Prints: Hello, Bob! + //sampleEnd } ``` {kotlin-runnable="true"} @@ -409,19 +409,19 @@ When the function body consists of a single expression, the curly braces can be ```kotlin fun main() { -//sampleStart -// Demonstrates a single-expression function with explicit return type -fun calculateArea(width: Int, height: Int): Int = width * height - -// Uses the function to calculate rectangle areas -val smallRectangle = calculateArea(2, 3) -println("Small rectangle area: $smallRectangle") -// Prints: Small rectangle area: 6 - -val largeRectangle = calculateArea(10, 20) -println("Large rectangle area: $largeRectangle") -// Prints: Large rectangle area: 200 -//sampleEnd + //sampleStart + // Demonstrates a single-expression function with explicit return type + fun calculateArea(width: Int, height: Int): Int = width * height + + // Uses the function to calculate rectangle areas + val smallRectangle = calculateArea(2, 3) + println("Small rectangle area: $smallRectangle") + // Prints: Small rectangle area: 6 + + val largeRectangle = calculateArea(10, 20) + println("Large rectangle area: $largeRectangle") + // Prints: Large rectangle area: 200 + //sampleEnd } ``` {kotlin-runnable="true"} @@ -430,19 +430,19 @@ Explicitly declaring the return type is [optional](#explicit-return-types) when ```kotlin fun main() { -//sampleStart -// Demonstrates a single-expression function with type inference -fun calculateCircleArea(radius: Double) = Math.PI * radius * radius - -// Uses the function with different radius values -val smallCircle = calculateCircleArea(2.0) -println("Small circle area: %.2f".format(smallCircle)) -// Prints: Small circle area: 12.57 - -val largeCircle = calculateCircleArea(5.0) -println("Large circle area: %.2f".format(largeCircle)) -// Prints: Large circle area: 78.54 -//sampleEnd + //sampleStart + // Demonstrates a single-expression function with type inference + fun calculateCircleArea(radius: Double) = Math.PI * radius * radius + + // Uses the function with different radius values + val smallCircle = calculateCircleArea(2.0) + println("Small circle area: %.2f".format(smallCircle)) + // Prints: Small circle area: 12.57 + + val largeCircle = calculateCircleArea(5.0) + println("Large circle area: %.2f".format(largeCircle)) + // Prints: Large circle area: 78.54 + //sampleEnd } ``` {kotlin-runnable="true"} @@ -454,30 +454,30 @@ Functions with block body must always specify return types explicitly, unless it ```kotlin fun main() { -//sampleStart -// Demonstrates a function requiring explicit return type due to complex logic -fun calculateGrade(score: Int): String { - if (score < 0 || score > 100) { - return "Invalid Score" - } + //sampleStart + // Demonstrates a function requiring explicit return type due to complex logic + fun calculateGrade(score: Int): String { + if (score < 0 || score > 100) { + return "Invalid Score" + } - return when { - score >= 90 -> "A" - score >= 80 -> "B" - score >= 70 -> "C" - score >= 60 -> "D" - else -> "F" + return when { + score >= 90 -> "A" + score >= 80 -> "B" + score >= 70 -> "C" + score >= 60 -> "D" + else -> "F" + } } -} -// Tests the function with different scores -println("Score 95: ${calculateGrade(95)}") -// Prints: Score 95: A -println("Score 85: ${calculateGrade(85)}") -// Prints: Score 85: B -println("Score -5: ${calculateGrade(-5)}") -// Prints: Score -5: Invalid Score -//sampleEnd + // Tests the function with different scores + println("Score 95: ${calculateGrade(95)}") + // Prints: Score 95: A + println("Score 85: ${calculateGrade(85)}") + // Prints: Score 85: B + println("Score -5: ${calculateGrade(-5)}") + // Prints: Score -5: Invalid Score + //sampleEnd } ``` {kotlin-runnable="true"} @@ -491,22 +491,22 @@ You can mark a parameter of a function (usually the last one) with the `vararg` ```kotlin fun main() { -//sampleStart -// Creates a list from a variable number of elements -fun createList(vararg elements: T): List { - // Converts vararg parameter to list - return elements.toList() -} + //sampleStart + // Creates a list from a variable number of elements + fun createList(vararg elements: T): List { + // Converts vararg parameter to list + return elements.toList() + } -// Demonstrates different ways to use vararg parameter -val numbers = createList(1, 2, 3, 4, 5) -println("Numbers: $numbers") -// Prints: Numbers: [1, 2, 3, 4, 5] + // Demonstrates different ways to use vararg parameter + val numbers = createList(1, 2, 3, 4, 5) + println("Numbers: $numbers") + // Prints: Numbers: [1, 2, 3, 4, 5] -val fruits = createList("apple", "banana", "orange") -println("Fruits: $fruits") -// Prints: Fruits: [apple, banana, orange] -//sampleEnd + val fruits = createList("apple", "banana", "orange") + println("Fruits: $fruits") + // Prints: Fruits: [apple, banana, orange] + //sampleEnd } ``` {kotlin-runnable="true"} @@ -518,29 +518,29 @@ Here's an example demonstrating more complex usage of varargs: ```kotlin fun main() { -//sampleStart -// Processes multiple items with a prefix -fun processItems(prefix: String, vararg items: String) { - items.forEach { item -> - println("$prefix: $item") + //sampleStart + // Processes multiple items with a prefix + fun processItems(prefix: String, vararg items: String) { + items.forEach { item -> + println("$prefix: $item") + } } -} -// Uses vararg with individual arguments -processItems("Item", "A", "B", "C") -// Prints: -// Item: A -// Item: B -// Item: C - -// Uses spread operator with an array -val moreItems = arrayOf("X", "Y", "Z") -processItems("Element", *moreItems) -// Prints: -// Element: X -// Element: Y -// Element: Z -//sampleEnd + // Uses vararg with individual arguments + processItems("Item", "A", "B", "C") + // Prints: + // Item: A + // Item: B + // Item: C + + // Uses spread operator with an array + val moreItems = arrayOf("X", "Y", "Z") + processItems("Element", *moreItems) + // Prints: + // Element: X + // Element: Y + // Element: Z + //sampleEnd } ``` {kotlin-runnable="true"} @@ -549,20 +549,20 @@ When working with primitive type arrays, you need to convert them to regular arr ```kotlin fun main() { -//sampleStart -// Demonstrates working with primitive arrays and varargs -fun sumNumbers(vararg numbers: Int): Int { - return numbers.sum() -} + //sampleStart + // Demonstrates working with primitive arrays and varargs + fun sumNumbers(vararg numbers: Int): Int { + return numbers.sum() + } -// Creates a primitive type array -val primitiveArray = intArrayOf(1, 2, 3) + // Creates a primitive type array + val primitiveArray = intArrayOf(1, 2, 3) -// Converts primitive array to regular array and uses spread operator -val sum = sumNumbers(*primitiveArray) -println("Sum: $sum") -// Prints: Sum: 6 -//sampleEnd + // Converts primitive array to regular array and uses spread operator + val sum = sumNumbers(*primitiveArray) + println("Sum: $sum") + // Prints: Sum: 6 + //sampleEnd } ``` {kotlin-runnable="true"} @@ -579,25 +579,25 @@ no [default value](#default-arguments) ```kotlin fun main() { -//sampleStart -// Defines a class with an infix function -class PairNumber(val value: Int) { - // Creates an infix function to pair numbers - infix fun pair(other: Int): Pair { - return Pair(this.value, other) + //sampleStart + // Defines a class with an infix function + class PairNumber(val value: Int) { + // Creates an infix function to pair numbers + infix fun pair(other: Int): Pair { + return Pair(this.value, other) + } } -} -// Uses the infix function notation -val number = PairNumber(1) -val pair1 = number pair 2 // Infix notation -val pair2 = number.pair(3) // Standard notation + // Uses the infix function notation + val number = PairNumber(1) + val pair1 = number pair 2 // Infix notation + val pair2 = number.pair(3) // Standard notation -println("Infix notation result: $pair1") -// Prints: Infix notation result: (1, 2) -println("Standard notation result: $pair2") -// Prints: Standard notation result: (1, 3) -//sampleEnd + println("Infix notation result: $pair1") + // Prints: Infix notation result: (1, 2) + println("Standard notation result: $pair2") + // Prints: Standard notation result: (1, 3) + //sampleEnd } ``` {kotlin-runnable="true"} @@ -606,21 +606,21 @@ Here's another example with a custom string operation: ```kotlin fun main() { -//sampleStart -// Defines an infix extension function for String -infix fun String.addSeparator(other: String): String { - return "$this -> $other" -} + //sampleStart + // Defines an infix extension function for String + infix fun String.addSeparator(other: String): String { + return "$this -> $other" + } -// Uses the infix function in different ways -val result1 = "Hello" addSeparator "World" // Infix notation -val result2 = "Kotlin".addSeparator("Fun") // Standard notation + // Uses the infix function in different ways + val result1 = "Hello" addSeparator "World" // Infix notation + val result2 = "Kotlin".addSeparator("Fun") // Standard notation -println(result1) -// Prints: Hello -> World -println(result2) -// Prints: Kotlin -> Fun -//sampleEnd + println(result1) + // Prints: Hello -> World + println(result2) + // Prints: Kotlin -> Fun + //sampleEnd } ``` {kotlin-runnable="true"} @@ -643,31 +643,31 @@ calling a method on the current receiver using the infix notation, use `this` ex ```kotlin fun main() { -//sampleStart -// Defines a collection class with an infix function -class StringCollection { - private val items = mutableListOf() - - // Defines an infix function to add items - infix fun add(item: String) { - items.add(item) - } + //sampleStart + // Defines a collection class with an infix function + class StringCollection { + private val items = mutableListOf() + + // Defines an infix function to add items + infix fun add(item: String) { + items.add(item) + } - // Demonstrates different ways to call the add function - fun addItems() { - this add "First" // Correct: uses infix notation with explicit receiver - add("Second") // Correct: uses standard notation - // add "Third" // Incorrect: receiver must be specified for infix notation + // Demonstrates different ways to call the add function + fun addItems() { + this add "First" // Correct: uses infix notation with explicit receiver + add("Second") // Correct: uses standard notation + // add "Third" // Incorrect: receiver must be specified for infix notation - println("Items in collection: $items") + println("Items in collection: $items") + } } -} -// Creates an instance and adds items -val collection = StringCollection() -collection.addItems() -// Prints: Items in collection: [First, Second] -//sampleEnd + // Creates an instance and adds items + val collection = StringCollection() + collection.addItems() + // Prints: Items in collection: [First, Second] + //sampleEnd } ``` {kotlin-runnable="true"} @@ -682,49 +682,49 @@ Here's an example demonstrating different function scopes: ```kotlin fun main() { -//sampleStart -// Top-level function (imagine this at file level) -fun calculateSquare(number: Int): Int { - return number * number -} + //sampleStart + // Top-level function (imagine this at file level) + fun calculateSquare(number: Int): Int { + return number * number + } -// Class with member function -class Calculator { - private var result: Int = 0 + // Class with member function + class Calculator { + private var result: Int = 0 - // Member function - fun add(number: Int) { - result += number - println("Current result: $result") - } + // Member function + fun add(number: Int) { + result += number + println("Current result: $result") + } - // Function with local function - fun calculateSumOfSquares(vararg numbers: Int) { - // Local function that can access outer scope - fun square(n: Int) = n * n + // Function with local function + fun calculateSumOfSquares(vararg numbers: Int) { + // Local function that can access outer scope + fun square(n: Int) = n * n - var sum = 0 - for (number in numbers) { - sum += square(number) // Uses local function + var sum = 0 + for (number in numbers) { + sum += square(number) // Uses local function + } + println("Sum of squares: $sum") } - println("Sum of squares: $sum") } -} -// Demonstrates usage of functions in different scopes -val square = calculateSquare(5) -println("Square of 5: $square") -// Prints: Square of 5: 25 + // Demonstrates usage of functions in different scopes + val square = calculateSquare(5) + println("Square of 5: $square") + // Prints: Square of 5: 25 -val calculator = Calculator() -calculator.add(3) -// Prints: Current result: 3 -calculator.add(7) -// Prints: Current result: 10 + val calculator = Calculator() + calculator.add(3) + // Prints: Current result: 3 + calculator.add(7) + // Prints: Current result: 10 -calculator.calculateSumOfSquares(2, 3, 4) -// Prints: Sum of squares: 29 -//sampleEnd + calculator.calculateSumOfSquares(2, 3, 4) + // Prints: Sum of squares: 29 + //sampleEnd } ``` {kotlin-runnable="true"} @@ -735,35 +735,35 @@ Kotlin supports local functions, which are functions inside other functions. Loc ```kotlin fun main() { -//sampleStart -// Demonstrates local functions with access to outer scope -fun processNumbers(numbers: List) { - var count = 0 - - // Local function that can access count from outer scope - fun incrementCountFor(predicate: (Int) -> Boolean) { - for (number in numbers) { - if (predicate(number)) { - count++ + //sampleStart + // Demonstrates local functions with access to outer scope + fun processNumbers(numbers: List) { + var count = 0 + + // Local function that can access count from outer scope + fun incrementCountFor(predicate: (Int) -> Boolean) { + for (number in numbers) { + if (predicate(number)) { + count++ + } } + println("Found $count numbers") } - println("Found $count numbers") - } - // Uses local function to count even numbers - incrementCountFor { it % 2 == 0 } - // Prints: Found {number of even integers} numbers + // Uses local function to count even numbers + incrementCountFor { it % 2 == 0 } + // Prints: Found {number of even integers} numbers - count = 0 // Resets counter + count = 0 // Resets counter - // Uses local function to count numbers greater than 5 - incrementCountFor { it > 5 } - // Prints: Found {number of integers > 5} numbers -} + // Uses local function to count numbers greater than 5 + incrementCountFor { it > 5 } + // Prints: Found {number of integers > 5} numbers + } -// Tests the function with a list of numbers -processNumbers(listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) -//sampleEnd + // Tests the function with a list of numbers + processNumbers(listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) + //sampleEnd } ``` {kotlin-runnable="true"} @@ -774,49 +774,49 @@ A member function is a function that is defined inside a class or object: ```kotlin fun main() { -//sampleStart -// Defines a class representing a bank account -class BankAccount(private var balance: Double) { - // Member function to deposit money - fun deposit(amount: Double) { - if (amount > 0) { - balance += amount - println("Deposited $amount. New balance: $balance") - } else { - println("Invalid deposit amount") + //sampleStart + // Defines a class representing a bank account + class BankAccount(private var balance: Double) { + // Member function to deposit money + fun deposit(amount: Double) { + if (amount > 0) { + balance += amount + println("Deposited $amount. New balance: $balance") + } else { + println("Invalid deposit amount") + } } - } - // Member function to withdraw money - fun withdraw(amount: Double) { - if (amount > 0 && amount <= balance) { - balance -= amount - println("Withdrawn $amount. New balance: $balance") - } else { - println("Invalid withdrawal amount or insufficient funds") + // Member function to withdraw money + fun withdraw(amount: Double) { + if (amount > 0 && amount <= balance) { + balance -= amount + println("Withdrawn $amount. New balance: $balance") + } else { + println("Invalid withdrawal amount or insufficient funds") + } } - } - // Member function to check balance - fun checkBalance() { - println("Current balance: $balance") + // Member function to check balance + fun checkBalance() { + println("Current balance: $balance") + } } -} -// Creates an account and performs operations -val account = BankAccount(100.0) -account.checkBalance() -// Prints: Current balance: 100.0 + // Creates an account and performs operations + val account = BankAccount(100.0) + account.checkBalance() + // Prints: Current balance: 100.0 -account.deposit(50.0) -// Prints: Deposited 50.0. New balance: 150.0 + account.deposit(50.0) + // Prints: Deposited 50.0. New balance: 150.0 -account.withdraw(70.0) -// Prints: Withdrawn 70.0. New balance: 80.0 + account.withdraw(70.0) + // Prints: Withdrawn 70.0. New balance: 80.0 -account.withdraw(100.0) -// Prints: Invalid withdrawal amount or insufficient funds -//sampleEnd + account.withdraw(90.0) + // Prints: Invalid withdrawal amount or insufficient funds + //sampleEnd } ``` {kotlin-runnable="true"} @@ -829,26 +829,26 @@ Functions can have generic parameters, which are specified using angle brackets ```kotlin fun main() { -//sampleStart -// Demonstrates a generic function that creates a list wrapper -class ListWrapper(private val item: T) { - fun getList(): List = listOf(item) -} + //sampleStart + // Demonstrates a generic function that creates a list wrapper + class ListWrapper(private val item: T) { + fun getList(): List = listOf(item) + } -// Generic function to create a ListWrapper -fun wrapInList(item: T): ListWrapper { - return ListWrapper(item) -} + // Generic function to create a ListWrapper + fun wrapInList(item: T): ListWrapper { + return ListWrapper(item) + } -// Uses the generic function with different types -val numberWrapper = wrapInList(42) -println("Number list: ${numberWrapper.getList()}") -// Prints: Number list: [42] + // Uses the generic function with different types + val numberWrapper = wrapInList(42) + println("Number list: ${numberWrapper.getList()}") + // Prints: Number list: [42] -val stringWrapper = wrapInList("Hello") -println("String list: ${stringWrapper.getList()}") -// Prints: String list: [Hello] -//sampleEnd + val stringWrapper = wrapInList("Hello") + println("String list: ${stringWrapper.getList()}") + // Prints: String list: [Hello] + //sampleEnd } ``` {kotlin-runnable="true"} @@ -864,34 +864,34 @@ the recursion, leaving behind a fast and efficient loop based version instead: ```kotlin fun main() { -//sampleStart -// Calculates factorial using tail recursion -tailrec fun factorial(n: Long, accumulator: Long = 1): Long = - when { - n <= 1 -> accumulator - else -> factorial(n - 1, n * accumulator) - } + //sampleStart + // Calculates factorial using tail recursion + tailrec fun factorial(n: Long, accumulator: Long = 1): Long = + when { + n <= 1 -> accumulator + else -> factorial(n - 1, n * accumulator) + } -// Tests factorial function with different numbers -println("Factorial of 5: ${factorial(5)}") -// Prints: Factorial of 5: 120 + // Tests factorial function with different numbers + println("Factorial of 5: ${factorial(5)}") + // Prints: Factorial of 5: 120 -println("Factorial of 10: ${factorial(10)}") -// Prints: Factorial of 10: 3628800 + println("Factorial of 10: ${factorial(10)}") + // Prints: Factorial of 10: 3628800 -// Demonstrates a more complex tail recursive function -// Finds the greatest common divisor using Euclidean algorithm -tailrec fun gcd(a: Int, b: Int): Int = - if (b == 0) a - else gcd(b, a % b) + // Demonstrates a more complex tail recursive function + // Finds the greatest common divisor using Euclidean algorithm + tailrec fun gcd(a: Int, b: Int): Int = + if (b == 0) a + else gcd(b, a % b) -// Tests GCD function with different number pairs -println("GCD of 48 and 36: ${gcd(48, 36)}") -// Prints: GCD of 48 and 36: 12 + // Tests GCD function with different number pairs + println("GCD of 48 and 36: ${gcd(48, 36)}") + // Prints: GCD of 48 and 36: 12 -println("GCD of 125 and 25: ${gcd(125, 25)}") -// Prints: GCD of 125 and 25: 25 -//sampleEnd + println("GCD of 125 and 25: ${gcd(125, 25)}") + // Prints: GCD of 125 and 25: 25 + //sampleEnd } ``` {kotlin-runnable="true"} @@ -900,28 +900,28 @@ The equivalent non-tail-recursive implementation would look like this: ```kotlin fun main() { -//sampleStart -// Non-tail-recursive factorial (less efficient, risk of stack overflow) -fun factorial(n: Long): Long = - if (n <= 1) 1 - else n * factorial(n - 1) // Not tail recursive: multiplication after recursive call - -// Traditional loop-based implementation -fun factorialLoop(n: Long): Long { - var result = 1L - for (i in 1..n) { - result *= i + //sampleStart + // Non-tail-recursive factorial (less efficient, risk of stack overflow) + fun factorial(n: Long): Long = + if (n <= 1) 1 + else n * factorial(n - 1) // Not tail recursive: multiplication after recursive call + + // Traditional loop-based implementation + fun factorialLoop(n: Long): Long { + var result = 1L + for (i in 1..n) { + result *= i + } + return result } - return result -} -// Compares results of different implementations -val n = 5L -println("Tail recursive factorial: ${factorial(n, 1)}") -println("Non-tail recursive factorial: ${factorial(n)}") -println("Loop-based factorial: ${factorialLoop(n)}") -// All print: 120 -//sampleEnd + // Compares results of different implementations + val n = 5L + println("Tail recursive factorial: ${factorial(n, 1)}") + println("Non-tail recursive factorial: ${factorial(n)}") + println("Loop-based factorial: ${factorialLoop(n)}") + // All print: 120 + //sampleEnd } ``` {kotlin-runnable="true"} diff --git a/docs/topics/generics.md b/docs/topics/generics.md index 4a17b5ffda1..21edadaf906 100644 --- a/docs/topics/generics.md +++ b/docs/topics/generics.md @@ -378,6 +378,7 @@ arguments at runtime, and the compiler prohibits such `is`-checks such as ```kotlin if (something is List<*>) { something.forEach { println(it) } // The items are typed as `Any?` + // Prints: [value of each item in the list] } ``` @@ -422,9 +423,13 @@ val stringToStringList = somePair.asPairOf>() // Compiles b fun main() { println("stringToSomething = " + stringToSomething) + // Prints: stringToSomething = (items, [1, 2, 3]) println("stringToInt = " + stringToInt) + // Prints: stringToInt = null println("stringToList = " + stringToList) + // Prints: stringToList = (items, [1, 2, 3]) println("stringToStringList = " + stringToStringList) + // Prints: stringToStringList = (items, [1, 2, 3]) //println(stringToStringList?.second?.forEach() {it.length}) // This will throw ClassCastException as list items are not String } ``` diff --git a/docs/topics/idioms.md b/docs/topics/idioms.md index 82523d3d932..40b93eef491 100644 --- a/docs/topics/idioms.md +++ b/docs/topics/idioms.md @@ -49,6 +49,7 @@ if ("jane@example.com" !in emailsList) { ... } ```kotlin println("Name $name") +// Prints: Name [value of name variable] ``` Learn the difference between [Java and Kotlin string concatenation](java-to-kotlin-idioms-strings.md#concatenate-strings). @@ -59,12 +60,12 @@ Learn the difference between [Java and Kotlin string concatenation](java-to-kotl // Reads a string and returns null if the input can't be converted into an integer. For example: Hi there! val wrongInt = readln().toIntOrNull() println(wrongInt) -// null +// Prints: null // Reads a string that can be converted into an integer and returns an integer. For example: 13 val correctInt = readln().toIntOrNull() println(correctInt) -// 13 +// Prints: 13 ``` For more information, see [Read standard input.](read-standard-input.md) @@ -94,6 +95,7 @@ val map = mapOf("a" to 1, "b" to 2, "c" to 3) ```kotlin println(map["key"]) +// Prints: [value associated with "key" in the map] map["key"] = value ``` @@ -102,6 +104,7 @@ map["key"] = value ```kotlin for ((k, v) in map) { println("$k -> $v") + // Prints: [key] -> [value] } ``` @@ -371,7 +374,7 @@ a = b.also { b = a } ``` ## Mark code as incomplete (TODO) - + Kotlin's standard library has a `TODO()` function that will always throw a `NotImplementedError`. Its return type is `Nothing` so it can be used regardless of expected type. There's also an overload that accepts a reason parameter: diff --git a/docs/topics/interfaces.md b/docs/topics/interfaces.md index 85e5543b799..c16090aaa92 100644 --- a/docs/topics/interfaces.md +++ b/docs/topics/interfaces.md @@ -42,6 +42,7 @@ interface MyInterface { fun foo() { print(prop) + // Prints: [value of prop property] } } @@ -64,7 +65,7 @@ interface Named { interface Person : Named { val firstName: String val lastName: String - + override val name: String get() = "$firstName $lastName" } @@ -83,16 +84,20 @@ When you declare many types in your supertype list, you may inherit more than on ```kotlin interface A { fun foo() { print("A") } + // Prints: A fun bar() } interface B { fun foo() { print("B") } + // Prints: B fun bar() { print("bar") } + // Prints: bar } class C : A { override fun bar() { print("bar") } + // Prints: bar } class D : A, B {