More elegant handling of out-projected types?

#1

Given:

interface OutProvider<Out> {
    fun convert(inVal: Int): Out
    fun run(outVal: Out)
}
fun main(args: Array<String>) {
    val stringProvider = object: OutProvider<String> {
        override fun run(outVal: String) {
            System.err.println("in run: $outVal")
        }
        override fun convert(inVal: Int) = "str$inVal"
    }

    val floatProvider = object: OutProvider<Float> {
        override fun run(outVal: Float) {
            System.err.println("in run: $outVal")
        }
        override fun convert(inVal: Int) = inVal.toFloat()
    }

    val providers: List<OutProvider<*>> =
        listOf(stringProvider, floatProvider)

    // Approach 1 (doesn't compile)
    for (provider in providers) {
        val outVal = provider.convert(23)
        provider.run(outVal)
    }
}

Understandably I get a compile error about the out-projected type when I call provider.run.

Trying some other syntax with crossed fingers predictably didn’t pan out:

// Approach 2 (doesn't compile)
for (val <T> provider: OutProvider<T> in providers) {
    val outVal = provider.convert(23)
    provider.run(outVal)
}

I had high hopes for this one:

// Approach 3 (doesn't compile)
for (p in providers) {
    val <T> provider: OutProvider<T> = p
    val outVal = provider.convert(23)
    provider.run(outVal)
}

I finally resorted to:

// Approach 4 (compiles)
fun <T> convertAndRun(provider: OutProvider<T>, inVal: Int) {
    val outVal = provider.convert(inVal)
    provider.run(outVal)
}
for (provider in providers) {
    convertAndRun(provider, 23)
}

This seems awkward to have to define a local function and break the visual flow of the code just to help the compiler identify provider’s type. Is there an easier way to keep the logic within the for loop? Have I missed something obvious?