Can't use if/when assignment to return lambda with inferred parameter but can use if/when blocks

188 views Asked by At

I have function returning a lambda based on an input String condition using if statement, which works fine - using this modified example from Head First Kotlin:

fun getConversionLambda(str: String): (Double) -> Double {
    if (str == "CelsiusToFahrenheit")
        return { it * 1.8 + 32 }
    if (str == "KgToPounds")
        return { it * 2.204623 }
    return { it }
}

But since that's an obvious good place to use when instead, and I use the <function declaration> = <expression> format, including the return type, then at compile or pre-compile time, I get an Unresolved reference: it error:

fun getConversionLambda2(str: String): (Double) -> Double = when(str) {
    "CelsiusToFahrenheit" -> { it * 1.8 + 32 }
    "KgToPounds" -> { it * 2.204623 }
    else -> { it }
}

Even if I specify it as the result of return within the function block, or assign it to a variable first and then return, I still get the Unresolved reference error:

fun getConversionLambda3(str: String): (Double) -> Double {
    return when (str) {
        "CelsiusToFahrenheit" -> { it * 1.8 + 32 }
        "KgToPounds" -> { it * 2.204623 }
        else -> { it }
    }
}

Only way I could get it to work is by specifying the lambda's input variable-type in the lambda:

// and infers the `(Double) -> Double` return type correctly if removed
fun getConversionLambda4(str: String): (Double) -> Double = when(str) {
    "CelsiusToFahrenheit" -> { x: Double -> x * 1.8 + 32 }
    "KgToPounds" -> { x: Double -> x * 2.204623 }
    else -> { x: Double -> x }
}

(my main:)

fun main(args: Array<String>) {
    println("getCL: ${getConversionLambda("KgToPounds")(2.5)}")
//    println("getCL2: ${getConversionLambda2("KgToPounds")(2.5)}")
//    println("getCL3: ${getConversionLambda3("KgToPounds")(2.5)}")
    println("getCL4: ${getConversionLambda4("KgToPounds")(2.5)}")
    
}

Why does the if version not have a problem with it? It's obviously inferring the lambdas' parameter type and doing the one-param-it based on getConversionLambda's definition's explicit return type. So why not for the when-version 2 & 3? I'm on Kotlin v1.4.32.

Edit: It seems any 'expression assignment' version of if & when prduces this issue unless I explicitly specify the parameter type for the lambda:

// Unresolved reference: it
fun getConversionLambda1A(str: String): (Double) -> Double =
    if (str == "KgToPounds") { it * 2.204623 } else { it }

// Unresolved reference: it
fun getConversionLambda1B(str: String): (Double) -> Double {
    return if (str == "KgToPounds") { it * 2.204623 } else { it }
}

But these two versions with the lambda parameter specified don't produce the error:

// works
fun getConversionLambda1Aokay(str: String) =
    if (str == "KgToPounds") { x: Double -> x * 2.204623 } else { x: Double -> x }

// works
fun getConversionLambda1Bokay(str: String): (Double) -> Double {
    return if (str == "KgToPounds") { x: Double -> x * 2.204623 } else { x: Double -> x }
}
1

There are 1 answers

5
ruffCode On BEST ANSWER

The issue is that you're not within the scope of the passed in function when trying to reference "it". Just add braces and you're all set.

fun getConversionLambda1A(str: String): (Double) -> Double =
if (str == "KgToPounds") { { it * 2.204623 } } else { { it } }

fun getConversionLambda2(str: String): (Double) -> Double = when(str) {
"CelsiusToFahrenheit" -> {{ it * 1.8 + 32 }}
"KgToPounds" -> {{ it * 2.204623 }}
else -> {{ it }} }