that they can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions. You can operate with functions in any way that is possible for other non- function values.”
types list and a return type: (A, B) -> C denotes a type that represents functions taking two arguments of types A and B and returning a value of type C. • The parameter types list may be empty, as in () -> A. • Function types can optionally have an additional receiver type A.(B) -> C, which represents functions that can be called on a receiver object of A with a parameter of B and return a value of C. • Function type is just a syntactic sugar for an interface, but the interface cannot be used explicitly. Nevertheless we can use function types like interfaces, what includes using them as type arguments or implementing them.
Int) -> Int val square: (Int) -> Int val producePrinter: () -> () -> Unit val sum: (Int, Int) -> Int = { a, b -> a + b } class MyFunction : () -> Unit { override fun invoke() { println("I am called") } } fun main(args: Array<String>) { val function = MyFunction() println(sum(1, 2)) // Prints: 3 function() // Prints: I am called }
a, b -> a + b } fun greetFunction() { println("Hello") } val reference1 = ::sumTwoInt val reference2 = sumTwoInt val reference3 = ::greetFunction fun anotherSumTwoInt() = sumTwoInt fun anotherGreatFunction() = ::greetFunction
for representing values of some types the language considers particularly important. • Function literal is a special notation used to simplify how a function is defined. • Two types of function literals: Lambda expression & Anonymous function.
define a function. val greet: () -> Unit = { println("Hello") } val calculateTwoInt: (Int, Int) -> Int = { a, b -> a + b } val square: (Int) -> Int = { x -> x * x } val producePrinter: () -> () -> Unit = { { println("I am printing") } } val greet = { println("Hello") } val calculateTwoInt = { a, b -> a + b } val square = { x: Int -> x * x } val producePrinter = { { println("I am printing") } } greet() // Prints: Hello calculateTwoInt(2, 3) // Prints: 5 println(square(2)) // Prints: 4 producePrinter()() // Prints: I am printing
define a function. val greet: () -> Unit = fun() { println("Hello") } val calculateTwoInt: (Int, Int) -> Int = fun(a, b): Int { return a + b } val calculateTwoInt: (Int, Int) -> Int = fun(a, b) = a + b val square: (Int) -> Int = fun(x) = x * x val producePrinter: () -> () -> Unit = fun() = fun() { println("I am printing") } val greet = fun() { println("Hello") } val calculateTwoInt = fun(a: Int, b: Int): Int = a + b val square = fun(x: Int) = x * x val producePrinter = fun() = fun() { println("I am printing") }
println("A is doing something") } } interface B { fun doSomething() { println("B is doing something") } } class Test : A, B { override fun doSomething() { doSomething() // infinitely recursive call } } class Test : A, B { override fun doSomething() { super<A>.doSomething() // explicit receiver super<B>.doSomething() // explicit receiver } }
that is closely related to Kotlin extensions. Extension receiver represents an object that we define an extension for. • Dispatch receiver is a special kind of receiver existing when the extension is declared a member. It represents an instance of the class in which the extension is declared in.
} class NetworkRepository(val person: Person) { fun loadData() {} fun move() {} fun doSomething() { person.uploadToBackend(); // We can access extension here } fun Person.uploadToBackend() { //method from extension dispatch receiver loadData() //method from extension receiver // calls method defined in Person class move() // calls method defined in NetworkRepository class [email protected]() } } val person = Person() person.uploadToBackend() // Compilation error
this expressions: • In a member of a class, this refers to the current object of that class. • In an extension function or a function literal with receiver this denotes the receiver parameter that is passed on the left-hand side of a dot. • If this has no qualifiers, it refers to the innermost enclosing scope. To refer to this in other scopes, label qualifiers are used => this@label
class B { // implicit label @B fun Int.foo() { // implicit label @foo val a = this@A // A's this val b = this@B // B's this val c = this // foo()'s receiver, an Int val c1 = this@foo // foo()'s receiver, an Int val funLit = fun String.() { val d = this // funLit's receiver } val funLit2 = { s: String -> // foo()'s receiver, since enclosing lambda expression // doesn't have any receiver val d1 = this } } } }
Function types can optionally have an additional receiver type A.(B) -> C, which represents functions that can be called on a receiver object of A with a parameter of B and return a value of C. class Person(var abc: String) val addNickName: Person.(nickName: String) -> String = { nickName -> this.abc + " is " + nickName } fun main(arg: Array<String>) { println(addNickName(Person("Vinh"), "Vince")) }
squareWithoutReceiver: (Int) -> Int = { num -> num * num } val squareWithoutReceiver1: (Int) -> Int = { it * it } val squareWithReceiver: Int.() -> Int = { this * this } val squareWithReceiverFunc: Int.() -> Int = fun Int.() = this * this val squareWithReceiverFunc1 = fun Int.() = this * this val squareFunc = { this, this } // compile error
-> R): R = block() fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block() fun <T> T.apply(block: T.() -> Unit): T { block(); return this } fun <T> T.also(block: (T) -> Unit): T { block(this); return this } fun <T, R> T.let(block: (T) -> R): R = block(this) https://docs.google.com/spreadsheets/d/1P2gMRuu36pSDW4fdwE- fLN9fcA_ZboIU2Q5VtgixBNo/edit#gid=0
each function is an object, and it captures a closure, i.e. those variables that are accessed in the body of the function. Memory allocations (both for function objects and classes) and virtual calls introduce runtime overhead. • The inline modifier affects both the function itself and the lambdas passed to it: all of those will be inlined into the call site.
object expression, functions can be nested in Kotlin. Qualified returns allow us to return from an outer function. The most important use case is returning from a lambda expression. fun foo() { listOf(1, 2, 3, 4, 5).forEach { // non-local return directly to the caller of foo() if (it == 3) return print(it) } println("this point is unreachable") }
5).forEach lit@ { // local return to the caller of the lambda, i.e. the forEach loop if (it == 3) return@lit print(it) } print("done with explicit label") } val getMessage = lambda@ { response: Response -> if(response.code !in 200..299) { return@lambda “Error" // Return at labels } response.message }
that mustn’t allow non-local returns, especially when such lambda is passed to another execution context such as a higher order function that is not inlined, a local object or a nested function. inline fun higherOrderFunction(crossinline lambda: () -> Unit) { normalFunction { lambda() } } fun normalFunction(func: () -> Unit) { return } fun callingFunction() { higherOrderFunction { return //Error. Can't return from here. } }
language specialized to a particular application domain. This is in contrast to a general-purpose language (GPL), which is broadly applicable across domains.
(way how to solve the problem) but in more or less declarative way (just declare the task) in order to obtain the solution based on the given data. • External DSLs have their own custom syntax, have to write a full parser to process them. • Internal DSLs are particular ways of using a host language to give the host language the feel of a particular language.
= "John" age = 25 address { street = "Main Street" number = 42 city = "London" } } data class Person( var name: String? = null, var age: Int? = null, var address: Address? = null ) data class Address( var street: String? = null, var number: Int? = null, var city: String? = null )
25, address = Address( street = "Main Street", number = 42, city = “London" ) ) val person = person { name = "John" age = 25 address { street = "Main Street" number = 42 city = "London" } }
{ val p = Person() p.block() return p } fun Person.address(block: Address.() -> Unit) { address = Address().apply(block) } val person = person { name = "John" age = 25 address { street = "Main Street" number = 42 city = "London" } }
Date, var address: Address? ) data class Address( val street: String, val number: Int, val city: String ) val person = person { name = "John" dateOfBirth = "1980-12-01" address { street = "Main Street" number = 12 city = "London" } }
private var dob: Date = Date() var dateOfBirth: String = "" set(value) { dob = SimpleDateFormat("yyyy-MM-dd").parse(value) } private var address: Address? = null fun address(block: AddressBuilder.() -> Unit) { address = AddressBuilder().apply(block).build() } fun build(): Person = Person(name, dob, address) } class AddressBuilder { var street: String = “" var number: Int = 0 var city: String = "" fun build() : Address = Address(street, number, city) } fun person(block: PersonBuilder.() -> Unit): Person = PersonBuilder().apply(block).build()
val addresses: List<Address> ) data class Address( val street: String, val number: Int, val city: String ) val person = person { name = "John" dateOfBirth = "1980-12-01" addresses { address { street = "Main Street" number = 12 city = "London" } address { street = "Dev Avenue" number = 42 city = "Paris" } } }
addresses = mutableListOf<Address>() fun address(block: AddressBuilder.() -> Unit) { addresses.add(AddressBuilder().apply(block).build()) } fun build(): Person = Person(name, dob, addresses) } val person = person { name = "John" dateOfBirth = "1980-12-01" address { street = "Main Street" number = 12 city = "London" } address { street = "Dev Avenue" number = 42 city = "Paris" } }
val addresses = mutableListOf<Address>() fun addresses(block: ADDRESSES.() -> Unit) { addresses.addAll(ADDRESSES().apply(block)) } fun build(): Person = Person(name, dob, addresses) } class ADDRESSES: ArrayList<Address>() { fun address(block: AddressBuilder.() -> Unit) { add(AddressBuilder().apply(block).build()) } } val person = person { name = "John" dateOfBirth = "1980-12-01" addresses { address { street = "Main Street" number = 12 city = "London" } address { street = "Dev Avenue" number = 42 city = "Paris" } } }
application development faster and easier. It makes your code clean and easy to read, and lets you forget about rough edges of the Android SDK for Java. • Anko supports: Andorid components (Intent, dialog, logging,…), UI layouts, SQLite, Coroutines • https://github.com/Kotlin/anko
myModule = module { single { Controller(get()) } single { BusinessService() } } class MyApplication : Application() { override fun onCreate(){ super.onCreate() startKoin(this, listOf(myModule)) } } class MyActivity() : AppCompatActivity() { val service : BusinessService by inject() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val service : BusinessService = get() } }