Lukasz
Lukasz

Reputation: 2317

Resolving Overload resolution ambiguity

I don't understand why the following two into functions, would cause an Overload resolution ambiguity:

public fun <Fiz> Boo.into(block: FizMorphBuilder.() -> Unit): FizMorphBuilder defined in com.ltrojanowski.morph
public fun <Foo> Boo.into(block: FooMorphBuilder.() -> Unit): FooMorphBuilder defined in com.ltrojanowski.morph

Why doesn't kotlin know given the type parameter which one to choose when I explicitly specify the type boo.into<Foo>{}.morph()?

class FooMorphBuilder(
    var a: String?,
    var b: Double?,
    var c: Int?,
    var d: Float?,
    var e: List<String>?
) : MorphBuilder<Foo> {
    override fun morph(): Foo = Foo(a = a!!, b = b!!, c = c!!, d = d!!, e = e!!)
}

fun <Foo> Boo.into(block: FooMorphBuilder.() -> Unit): FooMorphBuilder = FooMorphBuilder(this.a,
        this.b, this.c, this.d, this.e).apply(block)

And

class FizMorphBuilder(
    var a: String?,
    var b: Double?,
    var c: Int?,
    var d: Float?,
    var e: List<String>?
) : MorphBuilder<Fiz> {
    override fun morph(): Fiz = Fiz(a = a!!, b = b!!, c = c!!, d = d!!, e = e!!)
}

fun <Fiz> Boo.into(block: FizMorphBuilder.() -> Unit): FizMorphBuilder = FizMorphBuilder(this.a,
        this.b, this.c, this.d, this.e).apply(block)

Can I resolve this somehow?

Upvotes: 0

Views: 1087

Answers (1)

Eugene Petrenko
Eugene Petrenko

Reputation: 4982

The functions from the JVM point of view have the same type after type erasure, it will be something like (in Java):

public void into(Boo boo, Fucntion1 block);

A function return type is not taken into account for such resolution at the JVM level.

Use the @JvmName("unique name") annotation with different parameters for each of the methods to ask Kotlin compiler to generate unique names for the methods at the JVM level.

UPD: You do not need the generic parameters for these functions, namely <Fiz> and <Foo>. You do not use them in the declarations, and Kotlin compiler cannot infer the types too

UPD2: The compiler will not be able to guess the type of the lambda that you call, so you may need to specify the type of it explicitly too, e.g.

val builder : FizMorphBuilder.() -> Unit = { /*the builder lambda */ }
val z = Boo().into(builder)

We use the declaration with an explicit type to explain what exact builder lambda signature we need at that point.

Upvotes: 2

Related Questions