This is the part 10 of series Java to Kotlin - Learning Simplified. I hope you are learning something new from every part. This part is about Kotlin offerings you will either like it or hate it. I personally like it. And yes, this is last part of our lovely and long series.

If you have not read part 9, please do here.

Index of this Part: Late Init, Delegator, Lazy, Coroutine




lateinit


Kotlin is a strict language. It forces developers to think clearly while architecting. immutability, mutability, nullability, are taken seriously. Every property has to be assigned OR abstract is mantra.

	// Kotlin
	var value:String  ❌ not assigned, not allowed
	var value:String? ❌ not assigned, not allowed

As we see, nullable or not, a property has to be assigned. But sometimes, there are cases you need a dependency which is just not yet ready. Tests are the best example. Another good example is Android View, you do not have the reference unless view is populated. There are two solutions in that case:

  1. Make the property mutable and nullable, assign null and later update
  2. Something better

In the first solution, even though you had assignt he property as soon as you could, the null checks will haunt you. You need to use ?. OR !!. wherever you are accessing the nullables even though you are sure you did assign the value.

	@Inject
	var someDependency:Type? = null

In the above snippet, Inject is used to inject the dependency but because of assignment rule, we had to make it nullable and assign null. Kotlin offers a solution:

lateinit

As the name says, I, the developer knows I am going to initialise the property before I use. So marking it late initialised short form lateinit, so the above example becomes:

	@Inject
	lateinit var someDependency:Type

There are three points to note here:

  1. lateinit and var, it only works with var and not with val. val is immutable, how can you say I will assign something later if fundamentally it can not be changed
  2. No one is stopping you to use the property without initialising it, compiler does not warn you. If you use it before initialised, you get UninitializedPropertyAccessException
  3. Custom getter and setter are not allowed with lateinit

My recommendation is not to use this extensively unless you really need it. Having strong null check at compile time saves a lot of headache

What if you need to initialise a val property later?

There could be any reason you can not use var with lateinit but you can not assign the val property immediately. With val you do not have the option of nullable + assign later as well. They are immutable by nature.

πŸ”₯ Delegator to the rescue




Delegator


In simple words, a delegator is an object which can be used instead of getter and setters. This is a Kotlin feature and nothing like it is present in Java. Let’s say you have a property β€˜canShowBanner which is used to decide whether to show an ad banner to user or not. Now instead of caching the value in your class, you want to delegate this to some common class, e.g preference manager` in Android. You can do following:

	// Kotlin delegator

	var canShowBanner: Boolean = SharedPrefDelegator()

	// OR if you need read only

	val canShowBanner: Boolean = SharedPrefDelegator()

πŸ’‘ Important point to note is: Delegated property can not have getter/setter

But how to implement the Delegator, There is a special syntax for a delegator methods:

	// Example
 class Delegate {
	operator fun getValue(
		thisRef: Any?,
		property: KProperty<*>
		): PropertyType {}
	operator fun setValue(
		thisRef: Any?,
		property: KProperty<*>, value: PropertyType
	) {}
 }

PropertyType above is the type of property you will use your delegator with, If used with String, then String, if used with Int, then it will be Int.

The magic is whenever getter of the property will be called, kotlin will delegate the call to getValue of your delegator. Similarly, when setter of the property will be called, Kotlin will delegate the call to setValue of your delegator.

πŸ’‘ Note: Delegator can be used with var and val both, No need to stress for val, setValue function is not needed inside your delegator.

Back to the question: What if you need to intialise a val property later?

The answer is Delegator

The keyword to use a delegator is by

You can back your val property with a delegator and everytime you will try to read the val, getValue of your delegator will be called. Let’s see in action:

	// Kotlin
 class Delegate {
	operator fun getValue(
		thisRef: Any?,
		property: KProperty<*>
		): Int {
	}

	class Sample{
		val prop:Int by Delegate()
	}
 }

Everytime prop will be accessed, getValue of your delegator will be called. It means 🀯 you can return anyvalue you want from the delegator and your val (even it is immutable) will return the different value. Yea, it takes time to sink in. I have been where you are.

πŸ”₯ Interestingly there is a utility in Kotlin called lazy




Lazy


In simple words, lazy is a function which accepts a lambda and returns a delegator. The implementation of the delegator caches the value you return from the lambda amd returns it everytime the property is accessed. I recommend you to read the implementation of Lazy interface in the kotlin package. Here is a snippet of code:

	// Kotlin
	val heading:TextView by lazy {
		findViewById(R.id.heading)
	}

In the above example, heading is a val but it will be assigned lazily when first accessed. As lazy is just returning a delegator, it can be used with both var and val




Coroutine


I am not exaggerating but if you want only one reason to try Kotlin, it is coroutine. You must be aware with the concept of threading if you want to get amazed. What Threads did to processes, Coroutines are doing to Threads. I believe this statement is enough in itself to help you understand what a coroutine is!

Threading 101 is: Process is heavy and threads are light. Process need their own memory space and Threads share the memory space in a process. Co-Routines are even lighter than Threads.

In simple words, we can say co-routines share the threads. Kotlin as a language is offering some thread pools and doing all the heavy lifting for you to share the threads. All you need is to use the syntax and you are doing parallel work in a light weight fashion.

Kindly note this is a huge topic and deserves a series on its own. This section is to get you familiar with it and ignite the spark.

First of all, CoRoutine come with a separate Kotlin dependency. It is in the Kotlin-Core. Ensure you have included this dependency.

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:x.x.x For Android developers, there is another one as well, It offers Android related implementation like Main Thread Dispatcher:

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:x.x.x

The simplest way to start a co-routine is to use some Coroutine builder, platform provides some of the builders. launch async runBlocking to name a new. Here is one sample:

	// Java
	new Thread(){
		public void run(){}
	}.start();
	doSomethingHere(); // parallel execution

	// Kotlin
	GlobalScope.launch {
		// do the work in background
	}
	doSomethingElse()
	// this will execute in parallel

You can think the scope as the life of the coroutine, in our case GlobalScope means life of the program running. However, similar to the threads, main program will not wait for all the threads to complete. It will simply finish on its own. There are other scopes possible like ViewModelScope in Android.

	// Java, start 1 million threads
	for(int i=0;i<1000000;i++){
		new Thread(){
			public void run(){
				sleep(1000);
			}
		}.start();
	}

	// Kotlin, start 1 million coroutines
	repeat(1000000){
		launch{
			delay(1000)
		}
	}

Here we started 1 million threads and 1 million coroutines. Thread code might make your computer crazy. Coroutines will run smooth. The reason is sleep literally blocks the thread where delay frees it.

Using Job

launch returns a Job which can be used to cancel OR join. Check the following code:

	// Kotlin
	val job = GlobalScope.launch {
		// do the work in background
	}
	job.join() // now main program will wait untill the job  (similar to java future)completes

πŸ”₯ suspend keyword

This is one of the unique keyword and feature Kotlin offers. If a function is marked suspend and you call it from a coroutine, the coroutine will not execute the next line after the function call unless the function finishes. There is nothing special till now. The catch is, even if the suspend function is using another async operation inside. The suspended function can invoke another parallel coroutine and the first coroutine will free up the thread untill the suspended function returns. That is what makes coroutines special over Threads. Let’s see an example:

launch{
	val user = async { fetchUserFromNetwork() }.await() (similar to java future)
	showUser(user)
}

suspend fun fetchUserFromNetwork(){
	// time taking operation
}

The code above looks sequential but in reality it is not. Coroutine take care of the heavy lifting and calls showUser only after fetchUserFromNetwork is returned. We could also use async inside the fetch method. There is nothing like this in Java.

You can also say: A coroutine is a light-weight thread. Like threads, coroutines can run in parallel, wait for each other and communicate. The biggest difference is that coroutines are very cheap, almost free: we can create thousands of them, and pay very little in terms of performance. True threads, on the other hand, are expensive to start and keep around. Coroutines are almost free.

Under the hood, Kotlin is using Threads only. So co-routines is not a replacement but just a better management.

I will write another series on coroutines. This section was just to show you that it exists. I recommend you to read official documentation here and here


Summary


We started this part with lateinit, we saw how can it be used with non-null var properties to assign the value later. Then we saw Delegators and figured they can be used to delegate get and set, lazy is a utility which returns a delegator which can be clubbed with both var and val and it uses the lambda you pass to assign the value. Finally, we touched co-routines, we just touched tip of the iceburg when it comes to coroutines. I recommend you to learn from official docs. I will write another series on coroutines some day.


Summary of the Series


Subscribe to newsletter and keep learning good stuff

Email

πŸ‘‰ If you like article, click on β™₯️ recommend and share on social πŸ‘₯ media.
πŸ‘‰ Feel free to comment πŸ’¬
πŸ‘‰ Follow me πŸ‘€ for the more interesting articles. Twitter Medium
πŸ‘‰ Subscribe to newsletter and keep learning