Javaru

Javaru

Kotlin Coroutine Confidence: Code does not run (pg 225)

When I run pets/v23 from page 225, I get a quick flash of the “control panel” window, and then the program exits. There is no output in the console other than:

Process finished with exit code 0

Same problem for pets/v24 .

For pets/v25 and pets/v26, I get a single window, and then after the 15 second delay, rather than a second slide show starting, the program exits.

book-kotlin-coroutine-confidence version B3

Marked As Solved

sam-cooper

sam-cooper

Author of Kotlin Coroutine Confidence

Wow, thanks for spotting this! I’m embarrassed I missed it.

Looks like the bug is in the suspending createWindow() function. When we invoke the block() parameter (which, by the way, I’ve renamed to onWindowOpened() after our previous thread), we call window.dispose() immediately afterwards. But the lambda function doesn’t just need to wait for its own code; it also has a CoroutineScope receiver which it can use to launch additional coroutines.

The solution is to wrap block()/onWindowOpened() with its own coroutineScope { … }:

suspend fun createWindow(
  title: String,
  onWindowOpened: suspend CoroutineScope.(JFrame) -> Unit
): Unit = withContext(Dispatchers.Main) {
  val window = JFrame(title)
  window.defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE
  window.size = Dimension(400, 300)
  launch {
    window.addWindowListener(object : WindowAdapter() {
      override fun windowClosed(e: WindowEvent) = this@launch.cancel()
    })
    window.isVisible = true
    try {
      coroutineScope { onWindowOpened(window) }
    } finally {
      window.dispose()
    }
  }
}

This ensures the try block waits for the child coroutines as well as the suspending code. Adding a CoroutineScope receiver to an already-suspending function is a bit of an unusual pattern—it’s something I’d only ever really do in higher-order functions like this one. You can see the same pattern in the launch() and async() functions. It’s really just a convenience thing. Without it, callers would still be able to launch child coroutines by adding a coroutineScope() block inside the lambda code block. In other words, the two working options would be:

  • createWindow(…) { launch { … } } + coroutineScope { onWindowOpened(window) }, or
  • createWindow(…) { coroutineScope { launch { … } } } + onWindowOpened(window)

Evidently I changed my mind halfway through implementing it, and ended up halfway between the two options.

I might add a quick note next to the original createWindow() function explaining this extra coroutineScope(), since it’s a little unusual.

Thank you again for reporting the bug!

Where Next?

Popular Pragmatic Bookshelf topics Top

lirux
Hi Jamis, I think there’s an issue with a test on chapter 6. I own the ebook, version P1.0 Feb. 2019. This test doesn’t pass for me: ...
New
mikecargal
Title: Hands-on Rust: question about get_component (page 295) (feel free to respond. “You dug you’re own hole… good luck”) I have somet...
New
gilesdotcodes
In case this helps anyone, I’ve had issues setting up the rails source code. Here were the solutions: In Gemfile, change gem 'rails' t...
New
Chrichton
Dear Sophie. I tried to do the “Authorization” exercise and have two questions: When trying to plug in an email-service, I found the ...
New
adamwoolhether
I’m not quite sure what’s going on here, but I’m unable to have to containers successfully complete the Readiness/Liveness checks. I’m im...
New
dsmith42
Hey there, I’m enjoying this book and have learned a few things alredayd. However, in Chapter 4 I believe we are meant to see the “>...
New
akraut
The markup used to display the uploaded image results in a Phoenix.LiveView.HTMLTokenizer.ParseError error. lib/pento_web/live/product_l...
New
kolossal
Hi, I need some help, I’m new to rust and was learning through your book. but I got stuck at the last stage of distribution. Whenever I t...
New
New
dachristenson
@mfazio23 Android Studio will not accept anything I do when trying to use the Transformations class, as described on pp. 140-141. Googl...
New

Other popular topics Top

AstonJ
A thread that every forum needs! Simply post a link to a track on YouTube (or SoundCloud or Vimeo amongst others!) on a separate line an...
New
PragmaticBookshelf
Tailwind CSS is an exciting new CSS framework that allows you to design your site by composing simple utility classes to create complex e...
New
AstonJ
Biggest jackpot ever apparently! :upside_down_face: I don’t (usually) gamble/play the lottery, but working on a program to predict the...
New
PragmaticBookshelf
Build efficient applications that exploit the unique benefits of a pure functional language, learning from an engineer who uses Haskell t...
New
New
New
sir.laksmana_wenk
I’m able to do the “artistic” part of game-development; character designing/modeling, music, environment modeling, etc. However, I don’t...
New
AstonJ
This is cool! DEEPSEEK-V3 ON M4 MAC: BLAZING FAST INFERENCE ON APPLE SILICON We just witnessed something incredible: the largest open-s...
New
AstonJ
This is a very quick guide, you just need to: Download LM Studio: https://lmstudio.ai/ Click on search Type DeepSeek, then select the o...
New
PragmaticBookshelf
A concise guide to MySQL 9 database administration, covering fundamental concepts, techniques, and best practices. Neil Smyth MySQL...
New

Sub Categories: