https://kotlinlang.org logo
#getting-started
Title
# getting-started
r

Rob Elliot

12/08/2023, 10:56 AM
I'm pretty sure I know the answer is "no", but is there any way to abstract over these function signatures?
Copy code
fun <         R> inTransaction(work: ()        -> R): ()        -> R
fun <A,       R> inTransaction(work: (A)       -> R): (A)       -> R
fun <A, B,    R> inTransaction(work: (A, B)    -> R): (A, B)    -> R
fun <A, B, C, R> inTransaction(work: (A, B, C) -> R): (A, B, C) -> R
// and so ad infinitum
the actual parameters & their types to
work
are irrelevant, but the returned function must have the same type, and as I decorate
work
in the body I want to pass all argument to it... I suppose I'm hoping for something like:
Copy code
fun <F: (_): _> inTransaction(work: F): F {
  return { _ -> work(_) }
}
🚫 1
r

Robert Williams

12/08/2023, 11:47 AM
Probably you've already considered this but I'd normally just define the <A, R> version and then A can be Unit for no params or a simple data class for any number of params
👍 1
y

Youssef Shoaib [MOD]

12/08/2023, 11:47 AM
I should turn this into a library at some point of time, but yes, you can:
Copy code
typealias Wrapper<R> = (() -> R) -> R

fun <R> inTransaction(): Wrapper<R> = { work ->
  // prepare transaction
  val result = work()
  // end transaction
  return result
}

infix fun <R> (() -> R).wrappedWith(wrapper: Wrapper<R>): () -> R = {
    wrapper {
        invoke()
    }
}
infix fun <T1, R> ((T1) -> R).wrappedWith(wrapper: Wrapper<R>): (T1) -> R = { t1 ->
    wrapper {
        invoke(t1)
    }
}
infix fun <T1, T2, R> ((T1, T2) -> R).wrappedWith(wrapper: Wrapper<R>): (T1, T2) -> R = { t1, t2 ->
    wrapper {
        invoke(t1, t2)
    }
}
infix fun <T1, T2, T3, R> ((T1, T2, T3) -> R).wrappedWith(wrapper: Wrapper<R>): (T1, T2, T3) -> R = { t1, t2, t3 ->
    wrapper {
        invoke(t1, t2, t3)
    }
}
You have to define a
wrappedWith
variant for each arity, but you define that once, and you can use it for any such Wrapper-esque function. The usage simply looks like:
Copy code
myFun wrappedWith inTransaction()
r

Rob Elliot

12/08/2023, 11:50 AM
Ah, that looks like it might be a nicer version of what I just wrote: https://gist.github.com/Mahoney/9f7ecc0640d70f746034e5f05d962b6b
y

Youssef Shoaib [MOD]

12/08/2023, 11:54 AM
Hopefully, Kotlin will have a proposal for decorators, which might allow abstracting over function types, and thus supporting this pattern
👍 1
w

Wout Werkman

12/13/2023, 10:33 AM
Sorry, could you explain how decorators enable variadic generics? @Youssef Shoaib [MOD]? Btw, Swift has their own variant of variadic generics, and I think it's a really ergonomic design, I hope Kotlin will draw inspiration from this if we ever were to consider them: https://github.com/apple/swift-evolution/blob/main/proposals/0393-parameter-packs.md
2 Views