The book "Kotlin. Programming for professionals "

image Hello, habrozhiteli! The book by Josh Skin and David Greenhall is based on the popular Kotlin Essentials course from Big Nerd Ranch. Vivid and useful examples, clear explanations of key concepts and fundamental APIs not only introduce the Kotlin language, but also teach how to use its capabilities effectively, and also allow you to master the JetBrains IntelliJ IDEA development environment.

It doesn't matter if you are an experienced developer who wants to go beyond Java, or are learning the first programming language. Josh and David will guide you from the basic principles to the advanced use of Kotlin so you can create reliable and efficient applications.

Who is this book for?

We (the authors) wrote this book for developers of different calibers: experienced Android developers who lack Java features, server code developers interested in Kotlin features, and also for beginners who decide to learn an effective compiled language.

This book may interest you in supporting Android, but it is not limited to programming on Kotlin for Android. Moreover, in this book, only one chapter - chapter 21 - discusses Kotlin programming techniques for Android. Nevertheless, if you are interested in the topic of using Kotlin to develop Android applications, this book will introduce you to the basic techniques that will simplify the process of writing Android applications on Kotlin.

Although Kotlin has been influenced by some other languages, you don’t need to know how they are designed to work successfully with Kotlin. From time to time, we will compare Java and Kotlin code. If you have experience developing in Java, this will help you understand the relationship between the two languages. And if you do not have such experience, examples of solving the same problems in another language will help you understand the ideas that influenced the formation of Kotlin.

How to use this book

This book is not a reference. Our goal is consistent learning of the Kotlin language. You will work with projects and learn the language in the process. For greater effect, we recommend that you try out all the code examples as you read the book. Working with examples will help you develop “muscle” memory and provide insights that allow you to move from one chapter to another.

Each next chapter is based on the previous one. We recommend not skipping chapters. Even if you have studied the topic while working with other languages, we suggest you at least read about it here: a lot of things are implemented differently in Kotlin. We'll start with introductory topics, such as variables and lists, and then move on to the techniques of object-oriented and functional programming to make you understand what makes Kotlin such a powerful tool. By the end of the book, you will go from a beginner to an advanced developer on Kotlin.

We want to add that you should not hurry: develop, use the Kotlin documentation at the link: , where there are answers to many questions that arise during the experiments.

Excerpt. Extensions

Extensions allow you to add functionality to a type without explicitly changing the type declaration. Use extensions with custom types, as well as with types you have no control over, such as List, String, and other types from the Kotlin standard library.
Extensions are an alternative to inheritance. They are well suited for adding functionality to a type if the class definition is not available to you or the class does not have an open modifier that allows you to create subclasses.

The Kotlin standard library often uses extensions. For example, the standard functions that you learned in Chapter 9 are declared extensions, and in this chapter you will see some examples of their declaration.

In this chapter, we will first work on the Sandbox project, and then apply this knowledge to optimize the NyetHack code. To begin with, open the Sandbox project and create a new file called Extensions.kt.

Extension Function Declaration

Your first extension allows you to add any degree of enthusiasm to String. Declare it in Extensions.kt.

Listing 18.1. Adding an extension for type String (Extensions.kt)

fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) 

Extension functions are declared in the same way as other functions, but with one difference: when defining an extension function, you also specify a type known as a receiving type to which the extension adds features. (Recall Chapter 9, where we called extensible types “receivers.”) For the addEnthusiasm function, an accepting String type is specified.

The body of the addEnthusiasm function is just one expression that returns a string: the contents of this and 1 or more exclamation points, depending on the value of the amount argument (1 is the default value). The this keyword refers to the instance of the destination object for which the extension is called (in this case, the String instance).
Now you can call the addEnthusiasm function for any instance of String. Try a new extension function by declaring a line in the main function and calling the addEnthusiasm extension function for it to display the result.

Listing 18.2. Calling a new extension for an instance of the String receiver object (Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun main(args: Array<String>) { println("Madrigal has left the building".addEnthusiasm()) } 

Run Extensions.kt and see if the extension function adds an exclamation mark to the string, as intended.

Is it possible to subclass String to add this capability to String instances? In IntelliJ, look at the source code for the String declaration by pressing the Shift key twice to open the Search Everywhere dialog box and enter “String.kt” in the search box. You will see this class declaration:

 public class String : Comparable<String>, CharSequence { ... } 

Since the open keyword is not in the declaration of the String class, you cannot subclass String to add new features through inheritance. As previously mentioned, extensions are a good option if you want to add functionality to a class that you cannot control or which cannot be used to create a subclass.

Superclass extension declaration

Extensions do not rely on inheritance, but they can be combined with inheritance to increase the scope. Try this in Extensions.kt: declare an extension for type Any with the name easyPrint. Since the extension is declared for Any, it will be available for all types. In main, replace the println function call with the easyPrint extension call to String.

Listing 18.3. Any extension (Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun Any.easyPrint() = println(this) fun main(args: Array<String>) { println("Madrigal has left the building".addEnthusiasm()).easyPrint() } 

Run Extensions.kt and make sure that the output has not changed.

Since you added the extension for the Any type, it is also available for subtypes. Add an extension call for Int.

Listing 18.4. easyPrint is available for all subtypes (Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun Any.easyPrint() = println(this) fun main(args: Array<String>) { "Madrigal has left the building".addEnthusiasm().easyPrint() 42.easyPrint() } 

Generic Extension Functions

But what if you want to print the line “Madrigal has left the building” before and after addEnthusiasm?

To do this, add the ability to call in the chain to the easyPrint function. You have already seen chains of function calls: functions can participate in a chain if they return a receiver object or another object for which subsequent functions can be called.
Update easyPrint to call the chain.

Listing 18.5. Change easyPrint to call chaining (Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun Any.easyPrint()= println(this): Any { println(this) return this } ... 

Now try calling the easyPrint function twice: before and after addEnthusiasm.

Listing 18.6. Call easyPrint twice (Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun Any.easyPrint(): Any { println(this) return this } fun main(args: Array<String>) { "Madrigal has left the building".easyPrint().addEnthusiasm().easyPrint() 42.easyPrint() } 

The code did not compile. The first easyPrint call was allowed, but addEnthusiasm did not. Look at the type information to see why this happens: click on easyPrint and press Control-Shift-P (Ctrl-P) and from the list of extensions that appear, select the first: ("Madrigal has left the building .easyPrint ()") (Fig. 18.1).

The easyPrint function returns the string for which it was called, but uses the Any type to represent it. addEnthusiasm is available only to String, so it cannot be called on the value returned by easyPrint.


To solve this problem, you can make a generalized extension. Update the easyPrint extension function and use the generic type as the acceptor instead of Any.

Listing 18.7. Generalizing easyPrint (Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun <T> AnyT.easyPrint(): AnyT { println(this) return this } ... 

Now, when the extension uses the parameter of the generalized type T as the receiver and returns T instead of Any, information about the specific type of the receiver object is passed down the chain (Fig. 18.2).


Try running Extensions.kt again. This time the line will be output twice:

 Madrigal has left the building Madrigal has left the building! 42 

Your new generalized extension function works with any type, and also processes information about it. Extensions that use generic types allow you to write functions that can work with a wide variety of types in a program.

Extensions for generic types are also available in the Kotlin standard library. For example, look at the declaration of the let function:

 public inline fun <T, R> T.let(block: (T) -> R): R { return block(this) } 

let is declared as a generic extension function, which allows it to work with all types. It takes a lambda, which takes a receiver object as an argument (T) and returns the value of some new type R.

Pay attention to the inline keyword, which we learned about in Chapter 5. The same advice that we gave earlier applies here: declaring an extension function as built-in, if it accepts a lambda, reduces memory costs.

»More details on the book can be found on the publisher’s website
» Contents
» Excerpt

25% discount on coupon for Khabrozhitel - Kotlin
Upon payment of the paper version of the book, an electronic book is sent by e-mail.


All Articles