0

I'm trying to implement something similar to this syntax in Kotlin

class MyClass() {
    fun before(init: () -> Unit): Unit {
        with(this) init
    }
    fun after(block: () -> Unit): Unit {
        with(this) block
    }
}

fun main () {
    var myClass = MyClass()
    myClass.before {
        var a = 5
    }
    myClass.after {
        println("Double of a is ${a * 2}")
    }
}

Right now this won't work because a cannot be resolved within after. I understand that this is due to the way the closures work.

My question is if there is some mechanism in Kotlin that would allow me to do this, create variables in a closure/extension in such a way that they would be stored in the receiver object and be accessible to other closures/extensions.

This is part of an effort to migrate a Groovy script to Kotlin.

Disclaimer: This is my very first go at Kotlin. I've read through the docs but I may be missing something (a lot). Feel free to just point at the right direction

EDIT: Adding compilable example

class Aa() {

    var a: Int = 0
    var bb: () -> Unit = null!!

    fun ww (block: () -> Unit) {
        bb = block
    }

    fun doit(block: () -> Unit) {
        with(bb) {
            block()
        }
    }

}

fun main(args: Array<String>) {
    val exec = fun Aa.(other: () -> Unit): Unit = other()

    aa.ww {
        var xx = 5
    }

    aa.doit {
        // println("with $xx") <- this fails
    }
}
Hartimer
  • 525
  • 6
  • 20
  • Kotlin, unlike Groovy, is a statically typed language, which means that it's not possible to store arbitrary values in an object which doesn't have the fields for those values. – yole May 31 '16 at 18:55
  • @yole the fact that Kotlin is a statically typed language is what prompted me to dive into this project in the first place. I was wondering if the compiler would be smart enough to understand these types of initializations, but I suppose that this would be way too complicated, especially if you start initializing on some other class/function and using the result somewhere else. – Hartimer May 31 '16 at 19:12
  • What kind of initialization is this supposed to understand? You're declaring a var in the scope of an anonymous function that is passed to the `MyClass.before` function. Once you hit the closing brace, that scope is closed and `var a` no longer exists. – Ruckus T-Boom May 31 '16 at 20:15
  • Also, what is the `with(this) init` line supposed to do? That won't even compile as it is. Why don't you just say `init()` to run the init function? (Same goes for `with(this) block`.) – Ruckus T-Boom May 31 '16 at 20:18
  • @RuckusT-Boom the objective would be to store the variable `a` inside instance `myClass` so then you could use `myClass.a` somewhere else. – Hartimer May 31 '16 at 20:19
  • I see. In which case @yole's answer was all you needed :) – Ruckus T-Boom May 31 '16 at 20:25
  • Thanks for the feedback @RuckusT-Boom . I added compilable code to my question, that's the code I've been using to try and figure this out. Seems to be a problem with the design, which took advantage of Groovy's dynamic types more than anything else. – Hartimer May 31 '16 at 20:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/113472/discussion-between-ruckus-t-boom-and-hartimer). – Ruckus T-Boom Jun 01 '16 at 02:58

1 Answers1

1

Kotlin is a statically typed language. It's not possible to store data inside the instance of an object for which there is no field inside that object.

You could define a property of type Map, and store the values inside that map, but you won't be able to access them using the regular property syntax unless you know in advance which values will be stored there.

yole
  • 92,896
  • 20
  • 260
  • 197