Skip to content

Implement parameterize as multi-shot coroutine #34

@BenWoodworth

Description

@BenWoodworth

This is not a planned feature, at least not yet, but this issue tracks how parameterize could work if it were implemented as a suspend block that resumes from each parameter instead of re-running the whole block

It could be implemented as a suspend point when declaring a parameter:

suspend operator fun Parameter.provideDelegate()

A parameter will be constructed only once (instead of every iteration). After that, there will be a suspend point when provideDelegate is called on it, and having the listed/computed arguments locked in. From there, parameterize's suspend block will resume from there once for each of the arguments as a multi-shot coroutine.

Benefits

  • performance: no need to re-run start of block
    • changes how code before a parameter behaves, since now only
  • performance: no need to validate that the block was deterministic
  • no need to throw ParameterizeContinue up the call stack for internal control flow
  • no requirement for the block to be deterministic
  • parameterOf is no longer a performance concern
    • lazy parameterize is no longer needed

Problems/Blockers

  • Marking provideDelegate as suspend is not supported as of Kotlin 2.0
    • Though that was a restriction with the K1 compiler architecture <----------------------------- LINK
    • And has been acknowledged as possible to support in K2 <-------------------------------------- LINK
  • Use inside other suspend blocks may (or may not) be an issue
    • E.g. parameterizing Kotest suites with
      context("group") {
          parameterize {
              // ...
              test("test") { // suspends with `context`'s coroutine scope, through parameterize's
              }
          }
      }
      

Implementation

Multi-shot coroutines should be possible as long as a coroutine continuation can be cloned, that way it can be resumed more than once.

For each platform:

  • On jvm, Roman Elizarov has a Gist of how this can be done here
  • For js, creating a shallow copy is also a common enough concept
  • And native should be similarly straightforward

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions