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?
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.