Colin Dodd

True, False, ¯\_(ツ)_/¯

If this is true, do this. If this is false, do that. But what about null?

If the user is logged in, show the “My Profile” button. If the user isn’t logged in, show the “Log In” button. It’s such a common thing to do that I’ve probably done it thousands, if not tens of thousands of times. It’s so common there are even jokes about it.

One of the major advantages of Kotlin is that it distinguishes between nullable objects and non-nullable objects. This includes the Boolean type:

private fun example() {
    val isLoggedIn = tryLogin()
    if (isLoggedIn) { /**/ }
}

// returns: Nullable Boolean
private fun tryLogin(): Boolean? { /**/ }

Except, this doesn’t work because isLoggedIn can now be in three states, true, false, and null. Whereas the if statement only works with non-nullable booleans. We can rectify this by explicitly checking the state:

if (isLoggedIn == true)

This works, and is readable, but when code reviewing it can be hard to distinguish this from a new beginner mistake, causing it to be incorrectly flagged as an error. That said, this seems to be the recommended suggestion from the Kotlin style guide.

An alternative that may be preferable, is to use when:

java when(isLoggedin) {  true -> {}  false -> {}  null -> {} }

This works well if you want to branch based on the state of the boolean, but perhaps is a bit too verbose if you only want to do something in only one of the booleans states.

Colin Dodd

Extending the View

Now you see me, now you don’t. Improving Android visibility with Kotlin extension functions

Extension functions are one of the most powerful features of Kotlin. They allow for classes to be extended with your own logic no matter how locked down the class is.

This gave me the opportunity to fix one of my personal pet peeves in Android.

Views have three states of visibility. VISIBLE, the view can be seen. INVISIBLE, the view can not be seen but it takes up the same amount of space as it would have done were it visible. GONE, the view can not be seen and it takes up no space.

So many times I have ended up in a situation where I want to set the visibility of a view based on the state of a boolean.

if (isLoggedIn) {
    button.visibility = View.VISIBLE
} else {
    button.visibility = View.GONE
}

Since views have three states there is no easy say to just map a boolean to visibility state. There is no setVisibility(true) – there has always had to be some wrapping logic. Well now that extension functions exist I can fix that once and for all:

private fun View.isVisible(shouldShow: Boolean) {
    visibility = if (shouldShow) View.VISIBLE else View.GONE
}

private fun example() {
    button.isVisible(isLoggedIn)
}

Finally! Now I can just call isVisible on any view with a boolean and the visibility of the view will be set to either VISIBLE or GONE. Of course, if you actually want views to become INVISIBLE, then you’ll need a second extension function. Or you could give your extension function a default argument:

private fun View.isVisible(bool: Boolean?, nonVisibleState: Int = View.GONE) {
    visibility = if (bool == true) View.VISIBLE else nonVisibleState
}

private fun example() {
    // this defaults to View.GONE
    button1.isVisible(isLoggedIn)

    // this uses View.INVISIBLE
    button2.isVisible(isLoggedIn, View.INVISIBLE)
}