Kotlin Basics
Kotlin is a general-purpose, class-based object-oriented language. Although not a functional language, it includes some functional design elements (e.g. higher order functions). Syntactically, it is similar to other C-style programming languages, with a number of modern advances.
Practically, it is an excellent general-purpose language that can replace Java in production environments.
Types
A type system is the set of rules that are applied to expressions in a propgramming language language. We differentiate different type systems by the types of rules that they apply:
- Strong typing: The language has strict typing rules, which are typically enforced at compile-time. The exact type of variable must be declared or fixed before the variable is used. This has the advantage of catching many types of errors at compile-time (e.g. type-mismatch).
 - Weak typing: These languages have looser typing rules, and will often attempt to infer types based on runtime usage. This means that some categories of errors are only caught at runtime.
 
Kotlin is a strongly typed language, where variables need to be declared, or the type known, at compile time. If a type isn’t strictly provided, Kotlin will infer the type at compile time (similar to ‘auto‘ in C++). The compiler is strict about this: if the type cannot be inferred at compile-time, an error will be thrown.
Variables
Kotlin uses the var keyword to indicate a variable, and Kotlin expects variables to be declared before use. Types are always placed to the right of the variable name. Types can be declared explicitly, but will be inferred if the type isn’t provided.
fun main() {
  var a:Int = 10
  var b:String = "Jeff"
  var c:Boolean = false
  var d = "abc"	   // inferred as a String
  var e = 5        // inferred as Int
  var f = 1.5      // inferred as Float
}All standard data-types are supported, and unlike Java, all types are objects with properties and behaviours. This means that your variables are objects with methods! E.g. "10".toInt() does what you would expect.
Supported Types
Integers
| Type | Size (bits) | Min value | Max value | 
|---|---|---|---|
| Byte | 8 | -128 | 127 | 
| Short | 16 | -32768 | 32767 | 
| Int | 32 | -2,147,483,648 (-2 31) | 2,147,483,647 (2 31- 1) | 
| Long | 64 | -9,223,372,036,854,775,808 (-2 63) | 9,223,372,036,854,775,807 (2 63- 1) | 
Floating Point Types
| Type | Size (bits) | Significant bits | Exponent bits | Decimal digits | 
|---|---|---|---|---|
| Float | 32 | 24 | 8 | 6-7 | 
| Double | 64 | 53 | 11 | 15-16 | 
Boolean
The type Boolean represents boolean objects that can have two values: true and false. Boolean has a nullable counterpart Boolean? that also has the null value.
Built-in operations on booleans include:
||– disjunction (logical OR)&&– conjunction (logical AND)!- negation (logical NOT)||and&&work lazily.
Strings
Strings are often a more complex data type to work with. In Kotlin, they are represented by the String type, and are immutable. Elements of a string are characters that can be accessed by the indexing operation: s[i], and you can iterate over a string with a for-loop:
fun main() {
  val str = "Sam"
  for (c in str) {
      println(c)
  }
}You can concatenate strings using the + operator. This also works for concatenating strings with values of other types, as long as the first element in the expression is a string (in which case the other element will be case to a String automatically):
fun main() {
  val s = "abc" + 1
  println(s + "def")
}Kotlin supports the use of string templates, so we can perform variable substitution directly in strings. It’s a minor but incredibly useful feature that replaces the need to concatenate and build up strings to display them.
fun main() {
  println("> Kotlin ${KotlinVersion.CURRENT}")
  val str = "abc"
  println("$str.length is ${str.length}")
  var n = 5
  println("n is ${if(n > 0) "positive" else "negative"}")
}is and !is operator
To perform a runtime check whether an object conforms to a given type, use the is operator or its negated form !is:
fun main() {
  val obj = "abc"
  if (obj is String) {
    print("String of length ${obj.length}")
  } else {
    print("Not a String")
  }
}In most cases, you don’t need to use explicit cast operators in Kotlin because the compiler tracks the is checks and explicit casts for immutable values and inserts (safe) casts automatically when needed:
fun main() {
  val x = "abc"
  if (x !is String) return
  println("x=${x.length}") // x is automatically cast to String
  val y = "defghi"
  // y is automatically cast to string on the right-hand side of `||`
  if (y !is String || y.length == 0) return
  println("y=${y.length}") // y must be a string with length > 0
}Immutability
Kotlin supports the use of immutable variables and data structures (mutable means that it can be changed; immutable structures cannot be changed after they are initialized). This follows best-practices in other languages (e.g. use of final in Java, const in C++), where we use immutable structures to avoid accidental mutation.
var: a standard mutable variable that can be changed or reassigned.val: an immutable variable that cannot be changed once initialized.
var a = 0       // type inferred as Int
a = 5           // a is mutable, so reassignment is ok
val b = 1	    // type inferred as Int as well
// b = 2	    // error because b is immutable
var c:Int = 10  // explicit type provided in this caseOperators
Kotlin supports a wide range of operators. The full set can be found on the Kotlin Language Guide.
+,-,*,/,%- mathematical operators=assignment operator&&,||,!- logical ‘and,’ ‘or,’ ’not’ operators==,!=— structural equality operators compare members of two objects for equality===,!==- referential equality operators are true when both sides point to the same object.[,]— indexed access operator (translated to calls ofgetandset)
NULL Safety
NULL is a special value that indicates that there is no data present (often indicated by the null keyword in other languages). NULL values can be difficult to work with in other programming languages, because once you accept that a value can be NULL, you need to check all uses of that variable against the possibility of it being NULL.
NULL values are incredibly difficult to manage, because to address them properly means doing constant checks against NULL in return values, data, and so on. They add inherent instability to any type system.
Tony Hoare invented the idea of a NULL reference. In 2009, he apologized for this, famously calling it his “billion-dollar mistake.”
In Kotlin, every type is non-nullable by default. This means that if you attempt to assign a NULL to a normal data type, the compiler is able to check against this and report it as a compile-time error. If you need to work with NULL data, you can declare a nullable variable using the ? annotation. Once you do this, you need to use specific ? methods. You may also need to take steps to handle NULL data when appropriate.
Conventions
- By default, a variable cannot be assigned a NULL value.
 ?suffix on the type indicates that it’s NULL-able.?.accesses properties/methods if the object is not NULL (“safe call operator”)?:elvis operator is a ternary operator for NULL data!!override operator (calls a method without checking for NULL, bad idea)
fun main() {
	// name is nullable
	var name:String? = null
	// only returns value if name is not null
	var length = name?.length
	println(length) // null
	// elvis operator provides an `else` value
	length = name?.length ?: 0
	println(length) // 0
}Generics
Generics are extensions to the type system that allows us to parameterize classes or functions across different types. Generics expand the reusability of your class definitions because they allow your definitions to work with many types.
We’ve already seen generics when dealing with collections:
val list: List<Int> = listOf(5, 10, 15, 20)In this example, <Int> is specifying the type that is being stored in the list. Kotlin infers types where it can, so we typically write this as:
val list = listOf(5, 10, 15, 20)We can use a generic type parameter in the place of a specific type in many places, which allows us to write code towards a generic type instead of a specific type. This prevents us from writing methods that might only differ by parameter or return type.
A generic type is a class that accepts an input of any type in its constructor. For instance, we can create a Table class that can hold differing values.
You define the class and make it generic by specifying a generic type to use in that class, written in angle brackets < >. The convention is to use T as a placeholder for the actual type that will be used.
fun main() {
	class Table<T>(t: T) {
	    var value = t
	}
	val table1: Table<Int> = Table<Int>(5)
	val table2 = Table<Float>(3.14f)
}A more complete example:
import java.util.*
class Timeline<T>() {
    val events : MutableMap<Date, T> = mutableMapOf()
    fun add(element: T) {
        events.put(Date(), element)
    }
    fun getLast(): T {
        return events.values.last()
    }
}
fun main() {
	val timeline = Timeline<Int>()
	timeline.add(5)
	timeline.add(10)
}Control Flow
Kotlin supports the style of control flow that you would expect in an imperative language, but it uses more modern forms of these constructs
if then else
if... then has both a statement form (no return value) and an expression form (return value).
fun main() {
  val a=5
  val b=7
  // we don't return anything, so this is a statement
  println("a=$a, b=$b")
  if (a > b) {
      println("a is larger")
  } else {
      println("b is larger")
  }
  val number = 6
  // the value from each branch is considered a return value
  // this is an expression that returns a result
  println("number=$number")
  val result =
    if (number > 0)
      "$number is positive"
    else if (number < 0)
      "$number is negative"
    else
      "$number is zero"
  println(result)
}
// a=5, b=7
// b is larger
// number=6
// 6 is positiveThis is why Kotlin does not have a ternary operator:
ifused as an expression serves the same purpose.
for in
A for in loop steps through any collection that provides an iterator. This is equivalent to the for each loop in languages like C#.
fun main() {
  val items = listOf("apple", "banana", "kiwifruit")
  for (item in items) {
  	println(item)
  }
  for (index in items.indices) {
  	println("item $index is ${items[index]}")
  }
  for (c in "Kotlin") {
    print("$c ")
  }
}
// apple
// banana
// kiwifruit
// item 0 is apple
// item 1 is banana
// item 2 is kiwifruit
// K o t l i nKotlin doesn’t support a C/Java style for loop. Instead, we use a range collection .. that generates a sequence of values.
fun main() {
  // invalid in Kotlin
  // for (int i=0; i < 10; ++i)
  // range provides the same funtionality
  for (i in 1..3) {
    print(i)
  }
  println() // space out our answers
  // descending through a range, with an optional step
  for (i in 6 downTo 0 step 2) {
    print("$i ")
  }
  println()
  // we can step through character ranges too
  for (c in 'A'..'E') {
    print("$c ")
  }
  println()
  // Check if a number is within range:
  val x = 10
  val y = 9
  if (x in 1..y+1) {
    println("fits in range")
  }
}
// 123
// 6 4 2 0
// A B C D E
// fits in rangewhile
while and do... while exist and use familiar syntax.
fun main() {
  var i = 1
  while ( i <= 10) {
    print("$i ")
    i++
  }
}
// 1 2 3 4 5 6 7 8 9 10when
when replaces the switch operator of C-like languages:
fun main() {
  val x = 2
  when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> print("x is neither 1 nor 2")
  }
}
// x == 2fun main() {
    val x = 13
    val validNumbers = listOf(11,13,17,19)
    when (x) {
    	0, 1 -> print("x == 0 or x == 1")
    	in 2..10 -> print("x is in the range")
    	in validNumbers -> print("x is valid")
    	!in 10..20 -> print("x is outside the range")
    	else -> print("none of the above")
  }
}
// x is validWe can also return a value from when. Here’s a modified version of this example:
fun main() {
    val x = 13
    val validNumbers = listOf(11,13,17,19)
    val response = when (x) {
        0, 1 -> "x == 0 or x == 1"
        in 2..10 -> "x is in the range"
        in validNumbers -> "x is valid"
        !in 10..20 -> "x is outside the range"
        else -> "none of the above"
    }
    println(response)
}
// x is validWhen is flexible. To evaluate any expression, you can move the comparison expressions into when statement itself:
fun main() {
    val x = 13
    val response = when {
        x < 0 -> "negative"
        x >= 0 && x <= 9 -> "small"
        x >=10 -> "large"
        else -> "how do we get here?"
    }
    println(response)
}
// largereturn
Kotlin has three structural jump expressions:
returnby default returns from the nearest enclosing function or anonymous functionbreakterminates the nearest enclosing loopcontinueproceeds to the next step of the nearest enclosing loop
Functions
Functions are preceded with the fun keyword. Function parameters require types, and are immutable. Return types should be supplied after the function name, but in some cases may also be inferred by the compiler.
Named Functions
Named functions has a name assigned to them that can be used to invoke them directly (this is the expected form of a “function” in most cases, and the form that you’re probably expecting).
// no parameters required
fun main() {
    println(sum1(1, 2))
    println(sum1(3,4))
}
// parameters which require type annotations
fun sum1(a: Int, b: Int): Int {
    return a + b
}
// return types can be inferred based on the value you return
// it's better form to explicitly include the return type in the signature
fun sum2(a: Int, b: Int) {
    a + b // Kotlin knows that (Int + Int) -> Int
}
// 3
// 7Single-Expression Functions
Simple functions in Kotlin can sometimes be reduced to a single line aka a single-expression function.
// previous example
fun sumOf(a: Int, b: Int):Int {
    return a + b
}
// this works since we evaluate a single expression
fun minOf(a: Int, b: Int) = if (a < b) a else b
fun main() {
    println(sumOf(5,10))
    println(minOf(10,20))
}
// 15
// 10Default arguments
We can use default arguments for function parameters. When called, a parameter with a default value is optional; if the caller does not provide the value, then the default will be used.
// Second parameter has a default value, so it’s optional
fun mult(a:Int, b:Int = 5): Int {
	return a * b
}
fun main() {
	println(mult(1)) // a=1, b=5 default
	println(mult(5,2)) // a=5, b=2
	// mult() would throw an error, since `a` must be provided
}Named parameters
You can (optionally) provide the parameter names when you call a function. If you do this, you can even change the calling order!
fun repeat(str:String="*", count:Int=1):String {
    return str.repeat(count)
}
fun main() {
	println(repeat()) // *
	println(repeat(str="#")) // *
	println(repeat(count=3)) // ***
	println(repeat(str="#", count=5)) // #####
	println(repeat(count=5, str="#")) // #####
}
// *
// #
// ***
// #####
// #####Variable-length arguments
Finally, we can have a variable length list of arguments:
fun sum(vararg numbers: Int): Int {
    var sum = 0
    for(number in numbers) {
        sum += number
    }
  return sum
}
fun main() {
    println(sum(1)) // 1
    println(sum(1,2,3)) // 6
    println(sum(1,2,3,4,5,6,7,8,9,10)) // 55
}
// 1
// 6
// 55Collections
A collection is a finite group of some variable numbers of items (possibly zero) of the same type. Objects in a collection are called elements.
Collections in Kotlin are contained in the kotlin.collections package, which is part of the Kotlin Standard Library.
These collection classes exist as generic containers for a group of elements of the same type e.g. List<Int> would be an ordered list of integers. Collections have a finite size, and are eagerly evaluated.
Kotlin offers functional processing operations (e.g. filter, map and so on) on each of these collections.
fun main() {
  val list = (1..10).toList() // generate list of 1..10
  println( list.take(5).map{it * it} ) // square the first 5 elements
}
// [1, 4, 9, 16, 25]Under-the-hood, Kotlin uses Java collection classes, but provides mutable and immutable interfaces to these classes. Kotlin best-practice is to use immutable for read-only collections whenever possible (since mutating collections is often very costly in performance).
{.compact}
| Collection Class | Description | 
|---|---|
| Pair | A tuple of two values. | 
| Triple | A tuple of three values. | 
| List | An ordered collection of objects. | 
| Set | An unordered collection of objects. | 
| Map | An associative dictionary of keys and values. | 
| Array | An indexed, fixed-size collection of objects. | 
A tuple is a data structure representing a sequence of n elements.
Pair
A Pair is a tuple of two values. Use var or val to indicate mutability. Theto keyword can be used to indicate a Pair.
fun main() {
  // mutable
  var nova_scotia = "Halifax Airport" to "YHZ"
  var newfoundland = Pair("Gander Airport", "YQX")
  var ontario = Pair("Toronto Pearson", "YYZ")
  ontario = Pair("Billy Bishop", "YTZ") // reassignment is ok
  // accessing elements
  val canadian_exchange = Pair("CDN", 1.38)
  println(canadian_exchange.first) // CDN
  println(canadian_exchange.second) // 1.38
  // destructuring
  val (first, second) = Pair("Calvin", "Hobbes") // split a Pair
  println(first) // Calvin
  println(second) // Hobbes
}
// CDN
// 1.38
// Calvin
// HobbesPairs are extremely useful when working with data that is logically grouped into tuples, but where you don’t need the overhead of a custom class., e.g. Pair for 2D points.
List
A List is an ordered collection of objects.
fun main() {
  // define an immutable list
  var fruits = listOf( "advocado", "banana")
  println(fruits.get(0))
  // advocado
  // add elements
  var mfruits = mutableListOf( "advocado", "banana")
  mfruits.add("cantaloupe")
  mfruits.forEach { println(it) }
  // sorted/sortedBy returns ordered collection
  val list = listOf(2,3,1,4).sorted() // [1, 2, 3, 4]
  list.sortedBy { it % 2 } // [2, 4, 1, 3]
  // groupBy groups elements on collection by key
  list.groupBy { it % 2 } // Map: {1=[1, 3], 0=[2, 4]}
  // distinct/distinctBy returns unique elements
  listOf(1,1,2,2).distinct() // [1, 2]
}
// advocado
// advocado
// banana
// cantaloupeSet
A Set is a generic unordered collection of unique elements (i.e. it does not support duplicates, unlike a List which does). Sets are commonly constructed with helper functions:
fun main() {
	val numbersSet = setOf("one", "two", "three", "four")
    println(numbersSet)
	val emptySet = mutableSetOf<String>()
    println(emptySet)
}
// [one, two, three, four]
// []Map
A Map is an associative dictionary containing Pairs of keys and values.
fun main() {
  // immutable reference, immutable map
  val imap = mapOf(Pair(1, "a"), Pair(2, "b"), Pair(3, "c"))
  println(imap)
  // {1=a, 2=b, 3=c}
  // immutable reference, mutable map (so contents can change)
  val mmap = mutableMapOf(5 to "d", 6 to "e")
  mmap.put(7,"f")
  println(mmap)
  // {5=d, 6=e, 7=f}
  // lookup a value
  println(mmap.get(5))
  // d
  // iterate over key and value
  for ((k, v) in imap) {
    print("$k=$v ")
  }
  // 1=a 2=b 3=c
  // alternate syntax
  imap.forEach { k, v -> print("$k=$v ") }
  // 1=a 2=b 3=c
  // `it` represents an implicit iterator
  imap.forEach {
    print("${it.key}=${it.value} ")
  }
  // 1=a 2=b 3=c
}
// {1=a, 2=b, 3=c}
// {5=d, 6=e, 7=f}
// d
// 1=a 2=b 3=c 1=a 2=b 3=c 1=a 2=b 3=cOperations
Collection classes (e.g. List, Set, Map, Array) have built-in operations for working with the data that they contain. These are functions that frequently accept other functions as parameters.
Filter
filter produces a new list of those elements that return true from a predicate function.
fun main() {
	val list = (1..100).toList()
	val filtered = list.filter { it % 5 == 0 }
    println(filtered)
	// 5 10 15 20 ... 100
	val below50 = filtered.filter { it in 0..49 }
    println(below50)
	// [5, 10, 15, 20]
}
// [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
// [5, 10, 15, 20, 25, 30, 35, 40, 45]Map
map produces a new list that is the results of applying a function to every element that it contains.
fun main() {
	val list = (1..100).toList()
	val doubled = list.map { it * 2 }
    println(doubled)
}
// 2 4 6 8 ... 200Reduce
reduce accumulates values starting with the first element and applying an operation to each element from left to right.
fun main() {
	val strings = listOf("a", "b", "c", "d")
	println(strings.reduce { acc, string -> acc + string }) // abcd
}
// abcdZip
zip combines two collections, associating their respective pairwise elements.
fun main() {
	val foods = listOf("apple", "kiwi", "broccoli", "carrots")
	val fruit = listOf(true, true, false, false)
    println(fruit)
	val results = foods.zip(fruit)
	println(results)
}
// [true, true, false, false]
// [(apple, true), (kiwi, true), (broccoli, false), (carrots, false)]A more realistic scenario might be where you want to generate a pair based on the results of the list elements:
fun main() {
	val list = listOf("123", "", "456", "def")
	val exists = list.zip(list.map { !it.isBlank() })
    println(exists)
	val numeric = list.zip(list.map { !it.isEmpty() && it[0] in ('0'..'9') })
    println(numeric)
}
// [(123, true), (, false), (456, true), (def, true)]
// [(123, true), (, false), (456, true), (def, false)]ForEach
forEach calls a function for every element in the collection.
fun main() {
	val fruits = listOf("advocado", "banana", "cantaloupe" )
	fruits.forEach { print("$it ") }
}
// advocado banana cantaloupeWe also have helper functions to extract specific elements from a list.
Take
take returns a collection containing just the first n elements. drop returns a new collection with the first n elements removed.
fun main() {
	val list = (1..50)
	val first10 = list.take(10)
	println(first10)
	val last40 = list.drop(10)
	println(last40)
}
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// [11, 12, 13, 14, 15, 16, 17, 18, 19, ...]First, Last, Slice
first and last return those respective elements. slice allows us to extract a range of elements into a new collection.
fun main() {
	val list = (1..50)
	val even = list.filter { it % 2 == 0 }
	println(even.first()) // 2
	println(even.last()) // 50
	println(even.slice(1..3)) // 4 6 8
}
// 2
// 50
// [4, 6, 8]