Kotlin - CodingFlower https://www.codingflower.com/category/kotlin Check news in the world of Senior Software Engineers! Thu, 07 Sep 2023 21:59:21 +0000 en hourly 1 Inline Functions in Kotlin: Pros and Cons https://www.codingflower.com/2023/09/07/inline-functions-in-kotlin-pros-and-cons https://www.codingflower.com/2023/09/07/inline-functions-in-kotlin-pros-and-cons#respond Thu, 07 Sep 2023 21:44:10 +0000 http://www.codingflower.com/?p=1881 Inline Functions in Kotlin: Pros and Cons Inline functions are a powerful tool that can…

The post Inline Functions in Kotlin: Pros and Cons appeared first on CodingFlower.

]]>
Inline Functions in Kotlin: Pros and Cons

Inline functions are a powerful tool that can be used to improve the performance of Kotlin code. However, they also have some drawbacks that should be considered before using them.

What is an inline function?

An inline function is a function that is copied into the code of the calling function instead of being called separately. This can improve performance by reducing the number of function calls that need to be made.

When to use inline functions

Inline functions should be used when the performance benefits outweigh the drawbacks. This is typically the case for functions that are called frequently, especially within loops or in performance-critical code.

Pros of inline functions

  • Performance optimization: Inline functions can improve performance by reducing the number of function calls that need to be made. This is because the function's code is copied into the code of the calling function, so there is no need to make a separate function call.
  • Control over function inlining: The inline modifier can be used to control when and where a function is inlined. This can be useful for ensuring that performance-critical functions are always inlined.

Cons of inline functions

  • Code size increase: Inline functions can increase the size of the compiled code, as the function's code is copied at every call site. This can be a concern for applications with limited memory resources.
  • Compile time increase: Inline functions can increase the compile time, as the compiler needs to analyze the function's code to determine if it can be inlined. This can be a concern for applications that need to be compiled quickly.
  • Complexity increase: Inline functions can make code more complex, as the function's code is copied into the code of the calling function. This can make the code more difficult to read and maintain.

When not to use inline functions

Inline functions should not be used when the performance benefits are not significant or when the drawbacks outweigh the benefits. This is typically the case for functions that are called infrequently or that are not performance-critical.

Conclusion

Inline functions are a powerful tool that can be used to improve the performance of Kotlin code. However, they should be used carefully, as they can also have some drawbacks. When deciding whether or not to use an inline function, it is important to consider the specific needs of the application.

The post Inline Functions in Kotlin: Pros and Cons appeared first on CodingFlower.

]]>
https://www.codingflower.com/2023/09/07/inline-functions-in-kotlin-pros-and-cons/feed 0
How to create Mono? https://www.codingflower.com/2021/12/18/how-to-create-mono https://www.codingflower.com/2021/12/18/how-to-create-mono#respond Sat, 18 Dec 2021 17:41:33 +0000 http://www.codingflower.com/?p=1873 How to create Mono ? In this article, I would like to show you several…

The post How to create Mono? appeared first on CodingFlower.

]]>
How to create Mono ?

In this article, I would like to show you several different ways of creating reactive Mono. I'll present how to:

  • create mono without any value
  • create mono with value
  • create mono which contains an exception
  • create eager mono
  • create lazy mono
  • create mono per new subscription

but first, let's start with a short intro about Mono<T> itself.

Mono<T>

In simple words Mono<T> is a customized version of Publisher<T> which is able to emit at most one item.

Create Mono without any value

The most basic version of Mono. This Mono will complete without emitting any item.
Let's test that.

    @Test
    fun `should create empty mono`() {
        val emptyMono = Mono.empty<String>()

        StepVerifier
            .create(emptyMono)
            .expectNextCount(0)
            .verifyComplete()
    }

Create Mono with value

It would be nice to have Mono with some value inside of it, to achieve that we can use just method which accepts any type of data and returns Mono<T>. We can say that we are wrapping given data with Mono.

    @Test
    fun `should create mono with value`() {
        val createdMono = Mono.just("Mono")

        StepVerifier
            .create(createdMono)
            .expectNext("Mono")
            .verifyComplete()
    }

Create Mono which contains exception

Due to the fact that exception exists and we have to deal with them there is also a possibility to create Mono which contains an exception.

    @Test
    fun `should create error mono`() {
        val monoError = Mono.error<RuntimeException> { RuntimeException("Some fishy exception") }

        StepVerifier
            .create(monoError)
            .expectError(RuntimeException::class.java)
            .verify()
    }

Create eager Mono

What does it mean eager Mono? Basically, when we create the Mono we would like to
emit it instantly, during the creation. The method from the second paragraph will do that
for us Mono.just() emits wrapped item at the instantiation time.

    @Test
    fun `mono just is eager`() {
        val atomicInteger = AtomicInteger(0)
        val eagerMono = Mono.just(atomicInteger.incrementAndGet())

        Assertions.assertEquals(1, atomicInteger.get())
    }

Inside the Mono we are incrementing atomicInteger, but we are never subscribing
to given eagerMono, but still, incrementation takes place.

Create lazy Mono

Lazy Mono is opposite to the eager Mono, so we are not emitting anything
straight away, we are waiting for a subscription. To achieve that we can use the method
fromCallable which takes Callable as a parameter.

    @Test
    fun `mono from callable is lazy`() {
        val atomicInteger = AtomicInteger(0)
        val lazyMono = Mono.fromCallable { atomicInteger.incrementAndGet() }

        Assertions.assertEquals(0, atomicInteger.get())
    }

Inside the Mono we are incrementing atomicInteger, but we are never subscribing
to lazeMono and incrementation doesn't take a place. To execute
atomicInteger.incrementAntGet() we have to subscribe lazyMono.

Create new Mono per each subscription

Method Mono.defer() will create a provider that will deliver the given Mono for each
subscriber. Let's analyze the example below.

    @Test
    fun `mono defer` () {
        val atomicInteger = AtomicInteger(0)

        val deferedMono = Mono.defer { Mono.just(atomicInteger.incrementAndGet()) }

        StepVerifier
            .create(deferedMono)
            .expectNext(1)
            .verifyComplete()

        StepVerifier
            .create(deferedMono)
            .expectNext(2)
            .verifyComplete()
    }

We are doing two subscriptions on the same deferedMono provider. The result is quite
simple to predict, each subscription executes incrementation emitted by Mono.just()
delivered by Mono.defer() creator.

The post How to create Mono? appeared first on CodingFlower.

]]>
https://www.codingflower.com/2021/12/18/how-to-create-mono/feed 0
Kotlin coroutines run blocking https://www.codingflower.com/2021/02/25/kotlin-coroutines-run-blocking https://www.codingflower.com/2021/02/25/kotlin-coroutines-run-blocking#respond Thu, 25 Feb 2021 00:23:23 +0000 http://www.codingflower.com/?p=1866 In this short article, I will explain how to use runBlocking with multiple threads. Let's…

The post Kotlin coroutines run blocking appeared first on CodingFlower.

]]>
In this short article, I will explain how to use runBlocking with multiple threads. Let's analyze the code below. This is a quite popular use case of coroutines utilization. We can imagine that we make two different calls to two different services asynchronously and return the combined response.

fun main() {
    val response =
        runBlocking {
            val responseA = async { callToServiceA() }
            val responseB = async { callToServiceB() }
            return@runBlocking "${responseA.await()} + ${responseB.await()}"
        }

    println(response)
}

suspend fun callToServiceA(): Int {
    println("Start -> Service A thread: ${Thread.currentThread().id}")
    delay(1000)
    println("End -> Service A thread: ${Thread.currentThread().id}")
    return Random(1).nextInt()
}

suspend fun callToServiceB(): Int {
    println("Start -> Service B thread: ${Thread.currentThread().id}")
    delay(1000)
    println("End -> Service B thread: ${Thread.currentThread().id}")
    return Random(1).nextInt()
}

That's how the results look like:

Start -> Service A thread: 1
Start -> Service B thread: 1
End -> Service A thread: 1
End -> Service B thread: 1
600123930 + 600123930

So we can easily notice that both asynchronous tasks use the same thread. Even though async block uses Default coroutine dispatcher, because context is inherited from the outer scope (in this case from runBlocking). If we don't specify any CoroutineDispatcher , then all coroutines will be running on the current thread.

How can we execute async in a different thread?

The solution will be very easy. We can change the context of runBlocking to context = Dispatchers.Default . Then the output of the above code snippet will be:

Start -> Service A thread: 14
Start -> Service B thread: 15
End -> Service A thread: 14
End -> Service B thread: 15
600123930 + 600123930

Finally, our async blocks run concurrently.

The post Kotlin coroutines run blocking appeared first on CodingFlower.

]]>
https://www.codingflower.com/2021/02/25/kotlin-coroutines-run-blocking/feed 0
Killing mutations with Kotlin https://www.codingflower.com/2021/01/24/killing-mutations-with-kotlin https://www.codingflower.com/2021/01/24/killing-mutations-with-kotlin#respond Sun, 24 Jan 2021 23:48:35 +0000 http://www.codingflower.com/?p=1861 What are these mutations? Why do we need them? Do we really need to kill…

The post Killing mutations with Kotlin appeared first on CodingFlower.

]]>
What are these mutations? Why do we need them? Do we really need to kill them?

Mutation - application modified by PIT test.

We are creating tests to check that our implementations are working as we want. We are keeping high test coverage, but how can we check that our test really works? Traditional test coverage measures only which code was executed in your tests. It doesn't mean that this test is able to detect errors, it means that this code was used during tests.

How can we deal with this problem? We can run our tests against automatically modified versions of our application code. When the application code changes, it should produce different results and cause the test to fail. If after modification the test doesn't fail it could be broken.

Mutation testing

Running modified versions of applications looks reasonable, but we aren't going to change our code by hand, we are going to use the PIT test.

PIT test is mutation testing system which is compatible with JVM.

Let`s consider example, we are testing method which returns true if value is positive and false if is not.

class Mutations {
    fun isPositive(value: Int): Boolean {
        return value > 0
    }
}

Here is simple Kotest test:

class MutationsTest : ShouldSpec({
    should("return true if value is bigger than zero") {
        val mutation = Mutations()

        mutation.isPositive(20) shouldBe true
        mutation.isPositive(-20) shouldBe false
    }
})

If we run this test in Intellij Idea with code coverage we will see 100% of code coverage and test of course passed.

The mutation report will show us that our test is not perfect.

Our test had three mutations, two of them are dead, but one is still alive, but why? We already had 100% code coverage. The edge case is a problem, the zero number. Mutation modified condition from > to >= . The fix for this situation is very simple, we have to put another test case for zero number, then all mutation will be dead. By default only a few mutations are active, but you can enable more.

Summary

Mutation testing is a quite good way to verify that your tests really detect faults in code instead of just improving code coverage. It's really easy to integrate with kotest framework. The sad thing is this project doesn't have a supportive community, there are almost 300 GitHub issues already. If we have a bigger amount of tests, running mutation testing takes much time, so I don't recommend attaching it to the pipeline. I would say, this tool should be more used when your application failing but your test are green and have high code coverage.

The post Killing mutations with Kotlin appeared first on CodingFlower.

]]>
https://www.codingflower.com/2021/01/24/killing-mutations-with-kotlin/feed 0
Kotlin Contracts – cooperation with the compiler https://www.codingflower.com/2021/01/11/kotlin-contracts-cooperation-with-the-compiler https://www.codingflower.com/2021/01/11/kotlin-contracts-cooperation-with-the-compiler#respond Mon, 11 Jan 2021 22:59:45 +0000 http://www.codingflower.com/?p=1850 Sometimes compiler needs help and more information. Kotlin contracts are a way to transmit more…

The post Kotlin Contracts – cooperation with the compiler appeared first on CodingFlower.

]]>
Sometimes compiler needs help and more information. Kotlin contracts are a way to transmit more information to the compiler.

Kotlin contracts with the custom contract are experimental, but the stdlib already uses it.

This is a new language mechanism, it allows developers to pass more detailed information to the compiler and let the compiler utilize and analyze more data.

The new mechanism gives new possibilities:

  • improving smartcasts analysis
  • improve variable initialization analysis

Improve smartcasts analysis

Smartcast dissappears whenever we extract any checks to a new function, to keep the same behavior we can apply kotlin contracts.

Let's imagine the situation when we want to make object validation before processing. Validation is not so simple so we decide to extract it to the new function.

private fun validateUserWithoutContract(user: User?) {
    if (user == null) {
        throw Exception("We have big problem!")
    }
        ...
}

When we try to reach properties of a given user object without a safe call, we will meet a compilation error.

fun processWithoutContract(user: User?) {
    validateUserWithoutContract(user)
    println(user.name)        // Compilation error
}

We know that this object cannot be null because we already make a null-check, but the compiler doesn't know that. Kotlin contracts allow us to pass this information to the compiler.

@ExperimentalContracts
private fun validateUserWithContract(user: User?) {
    contract {
        returns() implies (user != null)
    }
    if (user == null) {
        error("We have big problem!")
    }
}

With this contract assumption, we can use user.name to reach name property, without a safe-call outside of the function, so processWithoutContract method will compile without any errors. The example above is the good practice of using this feature, another good way of utilization is casting.

Improve variable initialization analysis for higher-order functions

Let's check the second part of the contracts, we can tell the compiler how many times a function will be called by callsInPlace and InvocationKind .

Kotlin contracts have four invocation kinds:

  • UNKNOWN - can't initialize var or val, doesn't have to return.
  • AT_MOST_ONCE - same as UNKNOWN.
  • AT_LEAST_ONCE - can initialize var, but can't be used to initialize val, has to return after returned in the block.
  • EXACTLY_ONCE- can initialize val and var, but also has to return after returned in the block.

Let's have a look at run function:

@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

This function uses EXACTLY_ONCE so it means that you can use it to initialization of var and val variables. That's why the below code will compile, without this contract statement compiler will complain about Captured values initialization is forbidden due to possible reassignment and suggest changing to var instead of val.

This example illustrates one of the most common ways to use kotlin contracts, the initialization of objects in lambdas.

fun main() {
    val website: Website
    run {
        website = Website("www.codingflower.com")
    }
    print(website)
}

Limitations

  • Contract has to be on the very first lines of the code.
  • It can be used only on top functions or member functions.
  • There is no verification of the contracts.

Summary

This mechanism works in compile-time, the developer may provide additional guarantees or restrictions, which could be utilized by the compiler to perform analysis. This is the solution for the problem when we know that the object is not null but we had to use a safe call because of removed smartcasting. Some of the functions in stdlib are annotated with contracts. This contract concept is nothing new because this mechanism is already implemented in C++.

The post Kotlin Contracts – cooperation with the compiler appeared first on CodingFlower.

]]>
https://www.codingflower.com/2021/01/11/kotlin-contracts-cooperation-with-the-compiler/feed 0