Inspired by Given from arrow, I made this small li...
# arrow
y
Inspired by Given from arrow, I made this small little utility function that has been really useful with context receivers. The advantage it has is that the `this@`convention doesn't work if you have multiple receivers that are of the same type but with generics (i.e 2 lists):
Copy code
context(A) fun <A> given(): A = this@A
sadly the type needs to be specified whenever
given
is used because it doesn't infer the type parameter from usage (it instead latches onto the closest receiver).
❤️ 2
g
Sorry if this is a dumb question -- but what does this do exactly?
y
oh It's just for when you have context receivers (with the new prototype) so that you can pick one out based on a type. For instance:
Copy code
context(List<Int>, List<String>, Long)
fun doSomething() {
    repeat(given<Long>() {
        println(given<List<Int>>().last())
        println(given<List<String>>().first())
    }
}
Because the recommended way is to use the
this@List
notation, which doesn't accomodate generics. This is inspired by
given
which used to be a feature in Arrow Meta that did almost the same thing
r
thanks for sharing @Youssef Shoaib [MOD], related, @Imran/Malic is moving the proofs plugin to its own repo and @Javier and I are working in providing:
Copy code
@Context annotation class Config
@Context annotation class Persistence


@Config fun a(): A = ...
@Persistence fun b(): B = ...

context(A, B)
fun foo() {}

materialize<@Config A, @Persistence B>.foo()
That is DI for context receivers in addition to namespaced isolated injection based on type resolution. No source codegen just compiler substitutions in FIR and IR. If FIR works as expected IDEa will tell you when you are missing provider and other resolution errors when materializing.
👀 1
😍 1
g
Because the recommended way is to use the
this@List
notation, which doesn't accomodate generics.
Ohhh, got it that makes perfect sense. I've used Scala 3's `given`/`using` so I'm a bit familiar with the context receivers concept but I didn't know it had this limitation -- thanks for sharing!
That is DI for context receivers in addition to namespaced isolated injection based on type resolution. No source codegen just compiler substitutions in FIR and IR.
That looks fantastic! One of the biggest uses I've had for
given
in Scala 3 was easy DI, since you can just declare singleton objects and then inject them with
(using config: Config)
How do the annotations work here exactly?
r
In scala implicit injection is scoped and you have to tag your types if you want name based or similar resolution. In our case in Kotlin injection will be coherent like in haskell (no local scopes or complex discovery of instances, only top level) . We provide an annotation`@Context` that users can use to create their own annotations. Each context resolves its types independently than other context. This allows you to have multiple provider of the same type without ambiguity for different contexts.
🙌 1
Orphan instances and local overrides of instances is allowed if you make your providers
internal
making them of higher priority in candidate resolution