title: How to correctly extend an existing MVVM UI component?
body: <p>In my Kotlin desktop application using TornadoFX, I have created an <code>AudioCard</code> layout (subclass of <code>VBox</code>) which has a few labels and basic audio player controls. This <code>AudioCard</code> has an <code>AudioCardViewModel</code> which handles events from the UI and an <code>AudioCardModel</code> which holds information like the title, subtitle, audio file path, etc. A simplified version is shown below.</p>
  
  <pre><code>data class AudioCardModel(
      var title: String,
      var audioFile: File
  )
  
  class AudioCardViewModel(title: String, audioFile: File) {
      val model = AudioCardModel(title, audioFile)
      var titleProperty = SimpleStringProperty(model.title)
  
      fun playButtonPressed() {
          // play the audio file from the model
      }
  }
  
  class AudioCard(title: String, audioFile: File) : VBox() {
      val viewModel = AudioCardViewModel(title, audioFile)
      init {
          // create the UI
          label(title) {
              bind(viewModel.titleProperty)
          }
          button("Play") {
              viewModel.playButtonPressed()
          }
  
      }
  }
  </code></pre>
  
  <p>Up until this point, I have tried to keep the code as general as possible, allowing myself or others to reuse this UI component in future applications that need to play audio. However, for my current application, it makes the most sense to have a more specialized version of this UI component that initializes itself directly from my data model class and can extend some of the actions. I've tried something like this (the required fields and classes from the previous code block were switched to <code>open</code>):</p>
  
  <pre><code>data class CustomAudioCardModel(
      var customData: CustomData
  )
  
  class CustomAudioCardViewModel(customData: CustomData)
      : AudioCardViewModel(customData.name, customData.file) {
      val model = CustomAudioCardModel(customData)
  
      override fun playButtonPressed() {
          super.playButtonPressed()
          // do secondary things only needed by CustomAudioCardViewModel
      }
  }
  
  class CustomAudioCard(customData: CustomData): AudioCard(customData.name, customData.file) {
      override val viewModel = CustomAudioCardViewModel(customData)
  }
  </code></pre>
  
  <p>Unfortunately, this isn't so straightforward. By overriding <code>viewModel</code> in <code>CustomAudioCard</code>, the <code>viewModel</code> property ceases to be final, causing a NullPointerException when the init function of the <code>AudioCard</code> superclass tries to use the view model to set up the title label before the child class has initialized the view model.</p>
  
  <p>I suspect there might be a way out of this by defining an <code>AudioCardViewModel</code> interface and/or using Kotlin's ability to delegate with the <code>by</code> keyword, but I'm under the impression that defining the interface (like in MVP) shouldn't be necessary for MVVM.</p>
  
  <p><strong>To summarize: What is the correct way to extend an existing MVVM control, specifically in the context of the Kotlin TornadoFX library?</strong></p>