Scoped variable assignment used inside if statement

Hi there:

I am currently working on an Android project using both Kotlin and C++, one thing I think pretty good about the C++ syntax is the scoped variable inside if statement.

For example:

if (auto controller = getController())
{
controller.do();
}
else
{
// controller ptr is invalid here and outside if statement
}

is there any similar way for kotlin to do so?

one possible way in my head is:

getController()?.let { controller ->
controller.do()
}

2 Likes

I’m not familiar with cpp and auto but I guess your code is the same as:

val controller = getController()
if(controller != null){
    controller.do()
} else {
    //controller ptr is null here and so you can't do ccontroller-stuff with it
}

If this is the case your code is similar to:

getController()
   ?.also { it.do() }
   ?: run{
        // controller ptr is invalid here and outside if statement
   }

And if controller.do cannot return null, it is also the same as:

getController()
   ?.also { it.do() }
   ?: run{
        // controller ptr is invalid here and outside if statement
   }

If on the other hand it does more checks, it would be the same as:

getController()
   ?.takeIf{ it.checkAlso() }
   ?.also { it.do() }
   ?: run{
        // controller ptr is invalid here and outside if statement
   }

or

getController()
   ?.takeUnless{ it.checkNot() }
   ?.also { it.do() }
   ?: run{
        // controller ptr is invalid here and outside if statement
   }

Note, I’m using also, let returns the result of the lambda (in this case controller.do()).
This means that if you use let and controller.do returns null, you would execute run as well.

that being said, I often use when:

when(val controller = getController()){
    null -> {
         //controller is accessible, but is evaluated to null, so you can't do controller-stuff with it.
    }
    else -> controller.do()
}

I use run, such that you could execute a block.
If you can have a simple statement instead, just replace run completely:

getController()
       ?.takeUnless{ it.checkNot() }
       ?.also { it.do() }
       // controller ptr is invalid here and outside if statement           
       ?: doSomething()

Or for when:

when(val controller = getController()){
    null -> doSomething()
    else -> controller.do()
}
5 Likes

I personally wouldn’t use the version with also. While it works I don’t think it’s readable, especially using ?: run {} for the null case. I much prefer the version using when.
also makes it seem like the main code is just some unimportant side effect, while the error handling in run is the important part. This is exactly the opposite of what is intended.

1 Like

using when looks good to me, what I want is actually the scoped access for the controller reference

controller is scoped to inside the when block. Isn’t that what you want?

1 Like