Kotlin

Extensions

Swift

Extension functions

                  fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}
                
                    public struct Array<Element> {
    mutating func swapAt(_ i: Int, _ j: Int)
}

                  
                  val list = mutableListOf(1, 2, 3)
list.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'list'
                
                    var list = [1, 2, 3]
list.swapAt(0, 2)

                  
                  fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}
                

Extensions are resolved statically

                  open class Shape
​
class Rectangle: Shape()
​
fun Shape.getName() = "Shape"
​
fun Rectangle.getName() = "Rectangle"
​
fun printClassName(s: Shape) {
    println(s.getName())
}    
​
printClassName(Rectangle())
                
Overriding declarations in extensions is not supported
                  class Example {
    fun printFunctionType() { println("Class method") }
}
​
fun Example.printFunctionType() { println("Extension function") }
​
Example().printFunctionType()
                
                    class Example {
    func printFunctionType() { print("Class method") }
}
​
extension Example {
    //Error: Invalid redeclaration of 'printFunctionType()'
    func printFunctionType() { print("Extension function") }
}
​
Example().printFunctionType()

                  
                  class Example {
    fun printFunctionType() { println("Class method") }
}
​
fun Example.printFunctionType(i: Int) { println("Extension function") }
​
Example().printFunctionType(1)
                
                    class Example {
    func printFunctionType() { print("Class method") }
}

extension Example {
    func printFunctionType(i: Int) { print("Extension function") }
}

Example().printFunctionType(i: 1)

                  

Nullable receiver

                  fun Any?.toString(): String {
    if (this == null) return "null"
    // after the null check, 'this' is autocast to a non-null type, so the toString() below
    // resolves to the member function of the Any class
    return toString()
}
                
                    extension Optional {
    func toString() -> String {
        guard let x = self else  {
            return "nil"
        }
        
        return "\(x)"
    }
}

                  

Extension properties

                  val <T> List<T>.lastIndex: Int
    get() = size - 1
                
                    extension Array {
    var lastIndex: Int {
        get {
            return count - 1
        }
    }
}

                  
                  val House.number = 1 // error: initializers are not allowed for extension properties
                
                    extension House {
    var number: Int {
        get { 1 }
    }
}

                  

Companion object extensions

                  class MyClass {
    companion object { }  // will be called "Companion"
}
​
fun MyClass.Companion.printCompanion() { println("companion") }
​
fun main() {
    MyClass.printCompanion()
}
                
                    class MyClass {}

extension MyClass {
    static func printCompanion() { print("static") }
}

MyClass.printCompanion()

                  

Scope of extensions

                  package org.example.declarations
 
fun List<String>.getLongestString() { /*...*/}
                
                    extension Array where Element == String {
    func getLongestString() -> String {
        return "..."
    }
}

                  
                  package org.example.usage
​
import org.example.declarations.getLongestString
​
fun main() {
    val list = listOf("red", "green", "blue")
    list.getLongestString()
}
                
                    let list = ["red", "green", "blue"]
list.getLongestString()

                  

Declaring extensions as members

                  class Host(val hostname: String) {
    fun printHostname() { print(hostname) }
}
​
class Connection(val host: Host, val port: Int) {
     fun printPort() { print(port) }
​
     fun Host.printConnectionString() {
         printHostname()   // calls Host.printHostname()
         print(":")
         printPort()   // calls Connection.printPort()
     }
​
     fun connect() {
         /*...*/
         host.printConnectionString()   // calls the extension function
     }
}
​
fun main() {
    Connection(Host("kotl.in"), 443).connect()
    //Host("kotl.in").printConnectionString(443)  // error, the extension function is unavailable outside Connection
}
                
                  class Connection {
    fun Host.getConnectionString() {
        toString()         // calls Host.toString()
        this@Connection.toString()  // calls Connection.toString()
    }
}
                
                  open class Base { }
​
class Derived : Base() { }
​
open class BaseCaller {
    open fun Base.printFunctionInfo() {
        println("Base extension function in BaseCaller")
    }
​
    open fun Derived.printFunctionInfo() {
        println("Derived extension function in BaseCaller")
    }
​
    fun call(b: Base) {
        b.printFunctionInfo()   // call the extension function
    }
}
​
class DerivedCaller: BaseCaller() {
    override fun Base.printFunctionInfo() {
        println("Base extension function in DerivedCaller")
    }
​
    override fun Derived.printFunctionInfo() {
        println("Derived extension function in DerivedCaller")
    }
}
​
fun main() {
    BaseCaller().call(Base())   // "Base extension function in BaseCaller"
    DerivedCaller().call(Base())  // "Base extension function in DerivedCaller" - dispatch receiver is resolved virtually
    DerivedCaller().call(Derived())  // "Base extension function in DerivedCaller" - extension receiver is resolved statically
}