kotlinhttp4k

Why Kotlin type inference does not work for functional interface?


I'm working on a http4k web app. Http4k has a nice functional scheme for http handlers and filters (aka interceptors).

typealias HttpHandler = (Request) -> Response

interface Filter : (HttpHandler) -> HttpHandler {...}

I wanted to write a simple filter so I created a function which returns a Filter

fun throwNotFoundResponses(): Filter {
    return { next: HttpHandler ->
        { request: Request ->
            val response = next(request)
            if (response.status == Status.NOT_FOUND) {
                throw NotFoundException()
            }
            response
        }
    }
}

// example usage
Filter.NoOp
        .then(throwNotFoundResponses())
        .then(routes(...))

However Kotlin complains (Line number edited to match the example above.)

NotFoundThrower.kt: (2, 12): Type mismatch: inferred type is (HttpHandler /* = (Request) -> Response */) -> (Request) -> Response but Filter was expected

Why Kotlin cannot infer the types are actually identical?


Solution

  • A Filter is an interface that extends (HttpHandler) -> HttpHandler, so it is a subclass of it, not a superclass.

    Maybe it's easier to see if you don't have functional syntax.

    open class Animal
    class Kitten: Animal()
    
    fun doSomething(): Kitten {
        // You cannot return an explicit Animal here, even though the Kitten implementation
        // has not defined any unique members or overridden anything. 
    }
    

    Your lambda is literally a (HttpHandler) -> HttpHandler and cannot be inferred to be a Filter any more than an arbitrary Animal could be cast to a Kitten. It doesn't matter that we didn't happen to add any functions to Kitten or override anything. It's mere declaration means it is a distinct subtype and the compiler will never assume otherwise.