Looking at this code in kotlinx.coroutines, I noticed something strange:
/**
* Returns a flow containing the results of applying the given [transform] function to each value of the original flow.
*/
public inline fun <T, R> Flow<T>.map(crossinline transform: suspend (value: T) -> R): Flow<R> = transform { value ->
return@transform emit(transform(value))
}
In the first line, the transform
used is clearly this.transform
(defined here). Shouldn't the transform
declared in the method parameter have been used instead, as it is in the second line?
To test this, I wrote a small class which tries to mimc this behaviour:
// flow.kt
class Flow(val name: String) {
public fun transform (transform: (Any) -> Unit): Flow {
return Flow("transformed")
}
public fun emit(value: Any) {
// do nothing
}
public fun map(transform: (Any) -> Unit): Flow = transform { value ->
return@transform(emit(transform(value)))
}
}
And I get the kind of warning I was expecting when I run kotlinc flow.kt
:
flow.kt:12:54: error: type mismatch: inferred type is Unit but Flow was expected
public fun map(transform: (Any) -> Unit): Flow = transform { value ->
^
flow.kt:12:66: error: cannot infer a type for this parameter. Please specify it explicitly.
public fun map(transform: (Any) -> Unit): Flow = transform { value ->
^
(Kotlin version as returned by kotlinc -version
is "kotlinc-jvm 1.6.10 (JRE 17.0.1 1)")
So why is it that the code defined in kotlinx.coroutines works? If I understand Kotlin's name shadowing rules correctly it shouldn't have.
CodePudding user response:
In kotlinx.couroutines
, the transform
parameter takes an argument of type T
. Hence, this.transform
is used when transform
is called with a lambda argument.
In your example, the transform
parameter takes an argument of type Any
. A lambda is an Any
and hence the parameter is being used instead of this.transform
. Replacing Any
with a type parameter will make your code compile too.