Kotlin nonlocal variables


#1

Is there any way to create nonlocal variables in Kotlin ? (if not, any plans ?)

Take the following example:

fun getSomething(): {
    val time = measureTimeMillis {
        val result =  client.get { url("example.com") }
    }
    this.logger("Took $time")
    return result // this doesn't work since result is not available in this scope
}

I would like to be able to create the variable result in the scope of measureTimeMills and return it in the function getSomething without having to declare a var as null and reassigning it in the block.
Otherwise what would be the best way to handle those situations ?


#2

Can you move the logging statement to the function measuring the time it takes?

fun getSomething(): Response {
    return measureTimeMillis(logger) {
        client.get { url("example.com") }
    }
}

#3

What I really ended up doing is create a measureTimeMillis that returns the result and the time it took but I was still curious to know if it is possible to create nonlocal variables in any way


#4

Non-local variables are not supported. You could work around them using wrapper objects that you pass to the function that sets the value. But this makes it less readable and introduces the possibility for null (which can be resolved using the upcoming contracts):

class Wrapper<T> {
    val value: T? = null
}

fun getSomething(): Response {
    val result = Wrapper<Response>()
    val time = measureTimeMilliis {
        result.value =  client.get { url("example.com") }
    }
    this.logger("Took $time")
    return result.value!!
}

Adding support for non-local variables would significantly change the semantics of Kotlin, so I think this is something that won’t be added.


#5

There is no need for such wrappers in Kotlin (not like in Java). You can assign value to variable even from inside lambda.


#6

If you have control over the function that takes the lambda, you can add a particular contract to it, enabling what you call nonlocal variable.

Contracts are available as an experimental feature in Kotlin 1.3


#7

D’oh, you are right of course:

fun getSomething(): Response {
    var result: Response? = null
    val time = measureTimeMilliis {
        result =  client.get { url("example.com") }
    }
    this.logger("Took $time")
    return result!!
}

#8

I think this would be more elegant:

inline fun <T> measureTimeMillis(block: () -> T): Pair<Long, T> {
    val start = System.currentTimeMillis()
    val res = block()
    return Pair(System.currentTimeMillis() - start, res)
}

fun main(args: Array<String>) {
    val (time, result) = measureTimeMillis { 
        //do something
        ArrayList<String>().apply { 
            add("Hello ")
            add("World!")
        }
    }
    println("It took ${time} milliseconds to generate this: \n")
    result.forEach(::print)
}

EDITED to reflect @roland.illig advice:

Nice one :slight_smile:


#9

Thank you all for your answers. I like to avoid declaring a var as null and then reassigning it. In my code I had the function that @lamba92 suggested. But this meant I couldn’t use the std library measureTimeMillis. So I was still curious to know if there was a way to declare nonlocal variables which as I understood is not possible in Kotlin :slight_smile:.


#10

There is no need to with 1.3 and contracts. Until that you can use lateinit - unfortunately you will have to use var (not val).


#11

Instead of val timeAndResult =, you can also write val (time, result) =.

This is called a destructuring declaration.


#12

@pdvrieze Could you please show us an example of how to do that with contracts ?


#13

See Lambda Invocation contracts from this article: https://realjenius.com/2018/09/11/contracts/