lyng/docs/advanced_topics.md
2025-06-02 14:02:01 +04:00

1.9 KiB

Advanced topics

Closures/scopes isolation

Each block has own scope, in which it can safely use closures and override outer vars. Lets use some lambdas to create isolated scopes:

var param = "global"
val prefix = "param in "

val scope1 = {
    var param = prefix + "scope1"
    param
}

val scope2 = {
    var param = prefix + "scope2"
    param
}

println(scope1())
println(scope2())
println(param)
>>> param in scope1
>>> param in scope2
>>> global
>>> void

One interesting way of using closure isolation is to keep state of the functions:

val getAndIncrement = {
    // will be updated by doIt()
    var counter = 0

    // we return callable fn from the block:
    fun doit() {
        val was = counter
        counter = counter + 1
        was
    }
}()
// notice using of () above: it calls the lambda block that returns
// a function (callable!) that we will use:
println(getAndIncrement())
println(getAndIncrement())
println(getAndIncrement())
>>> 0
>>> 1
>>> 2
>>> void

Inner counter is not accessible from outside, no way; still it is kept between calls in the closure, as inner function doit, returned from the block, keeps reference to it and keeps it alive.

The example above could be rewritten using inner lambda, too:

val getAndIncrement = {
    // will be updated by doIt()
    var counter = 0

    // we return callable fn from the block:
    {
        val was = counter
        counter = counter + 1
        was
    }
}()
// notice using of () above: it calls the lambda block that returns
// a function (callable!) that we will use:
println(getAndIncrement())
println(getAndIncrement())
println(getAndIncrement())
>>> 0
>>> 1
>>> 2
>>> void