regarding the Ktor integration, for the `putOrRais...
# arrow-contributors
p
regarding the Ktor integration, for the
putOrRaise
(and similar) helpers that take a payload parameter (implicitly receiving a la
fun <reified B: Any> Route.put(String, (B) -> Unit): Route
I'm hitting an overload ambiguity between the following:
Copy code
inline fun <reified B : Any, reified R> Route.putOrRaise(
  path: String,
  crossinline body: suspend RaiseRoutingContext.(B) -> R,
): Route
and
Copy code
public inline fun <reified R> Route.putOrRaise(
  path: String,
  crossinline body: suspend RaiseRoutingContext.() -> R,
): Route
when attempting to use the non-receiving form, i.e.
putOrRaise("/path") { "my result" }
. You could disambiguate either with
putOrRaise("/path") { -> "my result" }
or
putOrRaise<_>("/path") { "my result" }
but neither are intuitive or ergonomic to write. The only reasonable alternative I can think of is to rename the "receiving" helpers like
putOrRaiseReceiving
or
putReceivingOrRaise
or such, but again, not very ergonomic. Any other thoughts or ideas? Do we even need/want to include a "receiving" form of these, given a consumer could just use
put<B>("/path") { respondOrRaise { "my result " }
or
putOrRaise("/path") { val it = receiveOrRaise<T>() }
as needed?
interestingly it seems the presence (and not) of type arguments on the
put
equivalent pair (
fun Route.put(String, RoutingContext.() -> Unit)
vs
fun <R> Route.put(String, RoutingContext.(R) -> Unit)
) is enough to disambiguate - unfortunately both
putOrRaise
overloads need type args to reify either the input or output types.
y
Would a dummy unit parameter work? I.e:
Copy code
inline fun <reified B : Any, reified R> Route.putOrRaise(
  path: String,
  unit: Unit = Unit,
  crossinline body: suspend RaiseRoutingContext.(B) -> R,
): Route
I think this'll disambiguate them, and it'll also get chosen for
putOrRaise<T, _> { ... }
and
putOrRaise { t: T -> ... }
p
unfortunately not - I tried that with
marker: Nothing? = null
earlier and Unit just now - no luck
I think I've cracked it - having one of the bodies being a SAM interface seems to make it happy to distinguish, and priorities the no-arg lambda
y
Huh, that's really neat! It's
crossinline
anyways, so we don't lose out on much by doing that. I'll keep this trick in my back pocket!
a
going a bit back to basic, but why do you need two overloads in the first place? In most cases Kotlin syntax makes it so that you can use
putOrRaise("/path") { "my result" }
even for the first overload
p
The only reason was to mirror the existing ktor verb route handlers, of which put/post/patch also have overloads that pre-receive the request body.
> Do we even need/want to include a "receiving" form of these, given a consumer could just use
put<B>("/path") { respondOrRaise { "my result " }
or
putOrRaise("/path") { val it = receiveOrRaise<T>() }
as needed? It's why I raised this point though - I've personally never used the "pre-receiving" versions, always preferring to
call.receive
as/when needed. We can always add them later. That said, they're there now.