2016-03-01 26 views
9

Ho un modello di fabbrica semplice in cui l'implementazione viene determinata tramite la risoluzione di sovraccarico. Il problema è che il compilatore Kotlin si lamenta con "Ambiguità della risoluzione di sovraccarico .." per il lambda in linea.Kotlin: lambda in linea e ambiguità della risoluzione di sovraccarico

class Foo(){ 
    companion object Factory { 
     fun create(x: Int, f: (Int) -> Double) = 2.0 
     fun create(x: Int, f: (Int) -> Int) = 1 
    } 
} 

fun main(args:Array<String>){ 
    val a = Foo.create(1,::fromDouble) //OK 
    val b = Foo.create(1,::fromInt) //OK 
    val ambiguous = Foo.create(1){i -> 1.0} //Overload resolution ambiguity? 
} 


fun fromDouble(int:Int) = 1.0 
fun fromInt(int:Int) = 1 

Come funziona la risoluzione di sovraccarico compilatore risolvere Kotlin e perché è il lambda linea considerata ambigua?

+4

Questo sembra essere un bug, perché se lancio il lambda come '{i: Int -> 1.0} come (Int) -> Double' non c'è ambiguità, ma dice che il cast non è necessario. Inoltre, se estrapro il lambda in 'val l = {i: Int -> 1.0}' e lo uso, di nuovo non c'è ambiguità. Si prega di cercare il bug tracker per questo problema e se non è lì ne file uno nuovo: https://youtrack.jetbrains.com/issues/KT – hotkey

+1

Un'altra cosa interessante è che se si lancia il lambda come fa @hotkey, l'IDE dirà tu che non è necessario. Ma nel momento in cui lo rimuovi, si lamenta dell'ambiguità. –

+1

Grazie per l'input! Ho pensato che probabilmente era un bug. Presentato un rapporto all'indirizzo https://youtrack.jetbrains.com/issue/KT-11265 –

risposta

4

Il compilatore Kotlin risolve ogni espressione solo una volta. Quindi, quando il compilatore inizia la risoluzione per l'espressione lambda, dovrebbe conoscere i tipi di argomenti lambda. A causa di questo compilatore dovrebbe scegliere uno dei metodi createprima dello inizia a guardare dentro lambda.

Esempio:

fun foo(f: (Int) -> Int) = 1 
fun foo(f: (String) -> String) = "" 
val bar = foo { 
    println(it) 
    5 
} 

Qui non possiamo scegliere una delle funzioni foo perché nessuno di loro è più specifico che un altro, quindi non possiamo iniziare a risoluzione per l'espressione lambda, perché non sappiamo digitare per it.

Nel tuo esempio è in teoria possibile avviare la risoluzione per lambda prima di scegliere una funzione particolare perché per tutte le potenziali funzioni i tipi di argomenti lambda sono gli stessi. Ma è una logica non banale che potrebbe essere difficile da implementare.

+0

Questo è un peccato. La risoluzione del sovraccarico su lambda è molto utile per l'applicazione numerica. Diciamo che ho una classe matrix che funziona su float, double e int. Con la "risoluzione di sovraccarico" l'istanziamento sarebbe 'val ms = Mat44 {i, j -> 1.0}', ora sono costretto a scrivere 'val ms = Mat44 ({i: Int, j: Int -> 1.0} come (Int, Int) -> Double) 'che è semplicemente semplice e stupido per un compito così banale. Mille grazie @erokhins per un'ottima spiegazione! –

+0

Come soluzione temporanea è possibile creare funzioni con nomi diversi: 'divertente Mat44Int2Double (f: (Int, Int) -> Double) = Mat44 (f)'. Ma non è elegante ... – erokhins

+0

Sì, un po 'mi ricorda il buon vecchio ANSI C giorni :) –