'Patterns for lazy default parameters in Kotlin

I find myself quite often writing classes that depend on something that is potentially expensive to create, e.g. a WebClient. I want this dependency to be a parameter for maximum flexibility and testability. I found the following ways of achieving this and am not sure which one to pick.

Option A: null check in constructor

class MyWebAppClient(webclient: WebClient? = null) {

    private val webclient: WebClient

    init {
        this.webclient = webclient ?: generateMyWebAppClient()
    }
    ...
}

Usage examples:

MyWebAppClient()
MyWebAppClient(webclient)

Option B: lambda generating the param

class MyWebAppClient(private val webclient: () -> WebClient = { generateMyWebAppClient()}) {
    ...
}

Usage examples:

MyWebAppClient()
MyWebAppClient({ webclient })
MyWebAppClient { webclient }

Option C: initialised default param

class MyWebAppClient(private val webclient: WebClient = generateMyWebAppClient()) {
    ...
}

Usage examples:

MyWebAppClient()
MyWebAppClient(webclient)

Question

Are there any up- or downsides to any of these approaches beyond the obvious difference in readability? Does any of these pose a risk of memory leaks, or other unexpected behaviour?

My favourite is option C, since it's the easiest to write and read. A quick test also didn't reveal any unexpected behaviour. I am just a little hesitant, because similar code in Python would call the function at the time the function is parsed, rather than at execution time.



Solution 1:[1]

Option B is lazy-loading the object and when it comes to performance this is the way to go. If you want to improve the testability, you may want to introduce Factory that will create your object. Employing Factory will not alleviate your code from the lazy-loading (if you use kotlin Lazy) and lambdas in constructor (readability).

class MyWebAppClient(private val webclientFactory: WebClientFactory) {

   private val webClient by lazy { webclientFactory.create() } 

}
 

In tests you can either provide your own test factory implementation that will return mock WebClient or you can just mock the Factory to return mock WebClient

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1