Mastering Kotlin: The Ultimate Guide to Becoming a Productivity Ninja!

Mangesh Yadav
3 min readJul 11, 2023

--

This guide covers most of what you need to know to be a Productivity Ninja and supercharge your development skills.

We will explore Kotlin’s powerful features, syntax, and best practices. Discover how to write clean, efficient, and maintainable code. Practical examples, and code snippets for your learning, while we highlight best practices for optimized performance and readability.

Here are some Kotlin features that will boost your productivity and reduce boilerplate.

  • Delegated Properties
  • Type aliases
  • Extensions
  • Function literals with receiver

Delegated Properties

If you have some common properties, even though you can implement them manually every time you need them, it is more helpful to implement them once. This is where Delegated Properties come in, you can create readOnly/readWrite (var/val)properties using ReadOnlyProperty<U,T> and ReadWriteProperty<U,T>

Let’s see an example of how we can delegate Fragment Arguments usingReadWriteProperty<U,T>

fun <T : Any?> fragmentArgs() = object : ReadWriteProperty<Fragment, T> {

override fun getValue(thisRef: Fragment, property: KProperty<*>): T =
thisRef.arguments?.get(property.name) as T

override fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
if (thisRef.arguments == null) thisRef.arguments = bundleOf()

thisRef.requireArguments().putAll(
bundleOf(property.name to value)
)
}
}

This is how we can set the arguments and read them.

// setting the arguments and initlizing the frgament
DelegateFragment().apply {
userId = "hello"
}

// inside DelegateFragment using the delegate fun
private var userId:String by fragmentArgs()

Type aliases

Type aliases are one of the most underused concepts of Kotlin. They are used to provide alternative names to existing types and to shorten long generic types.

// declaration 
typealias FileTable<K> = MutableMap<K, MutableList<File>>
typealias Collection<T> = MutableList<List<T>>

// usgae
private lateinit var table:FileTable<String>
private lateinit var list:Collection<String>

Type aliases are not limited to shortening collection names but can be used to give names for inner and nested classes and anonymous functions as well.

Extensions

Kotlin provides the ability to extend a class or an interface with new functionality without having to inherit from the class or use design patterns such as Decorator. This is done via special declarations called extensions.

We can use extensions not only for extending new functionality but also for reducing boilerplate. Most of us are already using Extensions but it’s worth emphasizing once more.

// extensions 
fun View.gone() {
if (this.visibility != View.GONE) {
this.visibility = View.GONE
}
}

fun View.invisible() {
if (this.visibility != View.INVISIBLE) {
this.visibility = View.INVISIBLE
}
}

public inline fun String?.orEmpty(): String = this ?: ""

// usage
textView.gone()
textView.invisible()
textView.text = name.orEmpty()

Function literals with receiver

Function types with receiver, such as A.(B) -> C, can be instantiated with a special form of function literals – function literals with receiver.

Inside the body of the function literal, the receiver object passed to a call becomes an implicit this, so that you can access the members of that receiver object without any additional qualifiers, or access the receiver object using a this expression.

You can create type-safe builders using Function literals with receiver


class HTML {
fun body() { }
}
// Function literals with receiver
fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // create the receiver object
html.init() // pass the receiver object to the lambda
return html
}

// usage

html {
body()
}

Another example of using function literals to reduce boilerplate.

// Function literals with receiver
inline fun IO(crossinline block: suspend CoroutineScope.() -> Unit) =
CoroutineScope(Dispatchers.IO).launch {
block.invoke(this)
}

// usage
IO{ //Coroutine with IO Dispatcher
repository.apiCall()
}

All of the above examples are about how we can leverage Kotlin’s features and syntax, but it’s not only limited to these examples.

Thanks for reading, Please feel free to provide any feedback.

If you’ve enjoyed my articles, Please follow me on Medium to continue our enriching exchange of ideas.

--

--

Mangesh Yadav
Mangesh Yadav

No responses yet