Alex Zaitsev
Alex Zaitsev

Reputation: 1781

Kotlin nested when

I have the next code. As you may see there are 3 when one inside another. Is it possible to flatten this code? I'm thinking about some wrapper but cannot get it. For now the only solution that I see is to move each when to the fun like processFirstWhen etc. Perhaps there is a cleaner solution. Any help appreciated.

when (val result = callback.invoke()) {
            is DataCompletable.Success -> DomainCompletable.Success
            is DataCompletable.Error ->
                when (result.error) {
                    is DataError.Unauthorized ->
                        when (tokenMixIn.refresh()) {
                            is DomainCompletable.Success -> execute(
                                currentNumberOfRetries + 1,
                                callback
                            )
                            is DomainCompletable.Error -> DomainCompletable.Error(DomainError.RefreshFailed)
                        }
                    else -> DomainCompletable.Error(result.error.mapToDomain())
                }

Upvotes: 3

Views: 6288

Answers (2)

Rahil Ali
Rahil Ali

Reputation: 965

Nested when structures are difficult to understand because you can easily confuse the cases of an inner when as belonging to an outer statement. Therefore nested when statements should be avoided.

Specifically, you should structure your code to avoid the need for nested when statements, but if you cannot, then consider moving the inner when to another function.

    when(val result =callback.invoke())
            {
                is DataCompletable.Success -> DomainCompletable.Success
                is DataCompletable.Error ->
                    errorCallBack(result.error)
            }
    
            

    fun errorCallBack(val error:Error) {
    
                when(error) {
                    is DataError.Unauthorized ->
                            when(tokenMixIn.refresh()) {
                        is DomainCompletable.Success -> execute(
                                currentNumberOfRetries + 1,
                                callback
                        )
                        is DomainCompletable.Error -> DomainCompletable.Error(DomainError.RefreshFailed)
                    }
                                else ->DomainCompletable.Error(result.error.mapToDomain())
                }
    
            }
        

Upvotes: 0

asm0dey
asm0dey

Reputation: 2931

Easy! But not using when.

What I suppose is to replace it with flat hierarchy of if's.

Like this:

val result = callback.invoke()
if(result is DataCompletable.Success) return DomainCompletable.Success
val error = result.error
if(error !is DataError.Unauthorized) return DomainCompletable.Error(result.error.mapToDomain())
val refreshResult = tokenMixIn.refresh()
if(refreshResult is DomainCompletable.Error) return DomainCompletable.Error(DomainError.RefreshFailed)
execute(currentNumberOfRetries + 1, callback)

Key aspect here is short-circuitness. We return result as soon as possible. But also we achieve flatter and easier to understand code.

Upvotes: 2

Related Questions