Initializing val properties in closure


#1

I'm using the builder pattern [1] to create DOM in Javascript. I've got a UI component class that looks something like below. It needs to build some DOM in its initializer, and save pieces of the DOM in properties.

class Pager() {
  val element: HTMLDivElement
  val previousLink: HTMLAnchorElement
  val nextLink: HTMLAnchorElement   
  {
           element = buildDiv {           
           lastLink =   a { +“Previous” }
           nextLink =   a { +“Next” }
           }
  }
}

The compiler thinks the vals are not initialized. But they would be, because buildDiv calls its function argument. Is there any way to tell compiler about this? I tried making buildDiv an inline function, but no luck.  

thanks,
Rob


[1] http://kotlinlang.org/docs/reference/type-safe-groovy-builders.html


Initializing vals in closure?
#2

As of today, there's no direct way of doing this.

The best thing I can offer at the moment is through a local variable:

class Pager() {

           val nextLink: HTMLAnchorElement   

    {

           var nl: HTMLAnchorElement? = null
           element = buildDiv {           
                     nl =   a { +“Next” }
           }
           this.nextLink = nl
  }
}


But this makes another case for one feature I was thinking about for a long time (something along the line of “this lambda is invoked by the call you are passing it to”), so thanks for your report.


#3

I agree, that seems like it would be a useful parameter annotation, and I guess the compiler could add it without my writing it.

Thanks for answering my recent slew of questions. I really like this language so far. I have yet to miss anything from Scala, and if this JS backend works well enough, I will be very happy. It’s been frustrating writing rich client apps in Javascript – 95% of my bugs are trivial type errors.

Rob


#4

abreslav wrote:

The best thing I can offer at the moment is through a local variable:


Mmm. Your local variable workaround stops working when Pager is inside another class, as it is in my real code.  A bug?

Rob


#5

May be a bug, could you show me the code?


#6

I just tried this with both backends. It compiles for JVM, but with JS backend I get the error, on both vals: Kotlin: Property must be initialized or be abstract

class Outer {
  class Pager() {

    val element: String
    val firstLink: String

    {

           var fl: String? = null

           element = buildDiv {
           fl = “First”
           }

           this.firstLink = fl!!
  }
  }
}


#7

It's bug. Please file it to tracker.

Anyway it will not work because right now the JS backend doesn’t support inner/nested/local traits and classes.

Thanks!


#8

Done. http://youtrack.jetbrains.com/issue/KT-5646


#9

Thanks!