Marius Kotsbak
12/08/2022, 12:09 PMinterface ServiceLocator<I> {
// fun getRealImpl(): I
fun getEmulatedImpl(): I
// fun getStubbedImpl(): I
}
context(ServiceLocator<I>)
inline fun <reified I> locateEmulated(): I = getEmulatedImpl()
object StringServiceLocator : ServiceLocator<String> {
override fun getEmulatedImpl(): String = "test"
}
object LongServiceLocator : ServiceLocator<Long> {
override fun getEmulatedImpl(): Long = 5
}
object StringLongLocatorFactory: ServiceLocatorFactory {
// In the future (scope properties): with val ...
inline fun <reified I> locate(): I {
with(LongServiceLocator) {
with(StringServiceLocator) {
return locateEmulated<I>()
}
}
}
}
No required context receiver found: Cxt { context(ServiceLocator<I>) public inline fun <reified I> locateEmulated(): I defined in [...] in file ServiceLocatorFactory.kt[SimpleFunctionDescriptorImpl@1aa4cbc9] }Marius Kotsbak
12/08/2022, 12:11 PMwith(StringServiceLocator) {
with(LongServiceLocator) {
val emulator = locateEmulated<String>()
}
}
but then it is not useful as I could just execute StringServiceLocator.getEmulatedImpl()
manually...Marius Kotsbak
12/08/2022, 12:20 PMobject StringLongLocatorFactory: ServiceLocatorFactory {
with val stringLocator = StringServiceLocator
with val longLocator LongServiceLocator
inline fun <reified I> locate(): I {
with(LongServiceLocator) {
with(StringServiceLocator) {
return locateEmulated<I>()
}
}
}
}
or more compact if possible. And String/Long are just examples of more complex stateful service classes.Youssef Shoaib [MOD]
12/08/2022, 3:47 PMI
was Int
or List<String>
or something? What behaviour do you expect to happen then?Marius Kotsbak
12/08/2022, 10:16 PMtrait ServiceLocator[I] {
// def getRealImpl(): I
def getEmulatedImpl: I
// def getStubbedImpl(): I
}
def summonEmulatedImpl[I](using locator: ServiceLocator[I]): I = locator.getEmulatedImpl
given stringServiceLocator : ServiceLocator[String] with {
def getEmulatedImpl: String = "test"
}
given longServiceLocator : ServiceLocator[Long] with {
def getEmulatedImpl: Long = 5L
}
object StringLongLocatorFactory {
def locateEmulated[I](using locator: ServiceLocator[I]): I = summonEmulatedImpl[I]
}
val stringRes: String = StringLongLocatorFactory.locateEmulated
println(stringRes)
val longRes = StringLongLocatorFactory.locateEmulated[Long]
println(longRes)
https://scastie.scala-lang.org/uRjg6FxGRLKjPt4ip7ORIAMarius Kotsbak
12/08/2022, 10:18 PM[error] ./ServiceLocatorFactory.sc:28:58: No given instance of type ServiceLocatorFactory.ServiceLocator[Int] was found for parameter locator of method locateEmulated in object StringLongLocatorFactory
[error] val intRes = StringLongLocatorFactory.locateEmulated[Int]
https://scastie.scala-lang.org/xQVxyhQQRl6QGITOZ43wxgYoussef Shoaib [MOD]
12/08/2022, 10:58 PMgiven
, it only has an equivalent to using
, which is context
. What you can do is have ServiceLocatorFactory take a ServiceLocator
parameter, but then I guess it won't really be a factory.Marius Kotsbak
12/09/2022, 8:26 AMYoussef Shoaib [MOD]
12/09/2022, 1:13 PMComparator<List<E>>
that relies on having a Comparator<E>
in scope, so if you define such a structure, you have to manually bring in an instance for Comparator<List<String>>
, Comparator<List<Int>>
and so on.Marius Kotsbak
12/09/2022, 1:42 PMobject StringLongLocatorFactory
but hopefully without a pyramid of `with`s, but either "with val", annotation on the class, or:
inline fun <reified I> locate(): I {
with(LongServiceLocator, StringServiceLocator) {
return locateEmulated<I>()
}
}
It looks like the problem is that is the resolving of the actual context variable is eager and can't be deferred to the actual calls to locate()
even when using reified
.Youssef Shoaib [MOD]
12/09/2022, 1:45 PMYoussef Shoaib [MOD]
12/09/2022, 1:50 PMcontext(ServiceLocator<I>)
inline fun <I> locate(): I {
return locateEmulated<I>()
}
But the key difference is that, when locate is called, Scala can globally find the required ServiceLocator instance, while with Kotlin you'll need something like a multi-with like so:
inline fun <A, B, R> with(a: A, b: B, block: context(A, B) () -> R): R = block(a, b)
Marius Kotsbak
12/09/2022, 1:54 PMYoussef Shoaib [MOD]
12/09/2022, 1:59 PMinline fun <R> serviceLocators(block: context(LongServiceLocator, StringServiceLocator) () -> R): R = block(LongServiceLocator, StringServiceLocator)
Maybe when decorators become a thing in Kotlin you could define the above function as a decorator, and then using it would be more idiomaticMarius Kotsbak
12/09/2022, 2:01 PMUberto Barbini
01/14/2023, 1:30 AMUberto Barbini
01/14/2023, 1:31 AMMarius Kotsbak
04/26/2023, 1:43 PMUberto Barbini
05/03/2023, 10:26 PMUberto Barbini
05/03/2023, 10:31 PMYoussef Shoaib [MOD]
05/04/2023, 9:53 AMinterface Monoid<T> {
val zero: T
operator fun T.plus(other: T): T
}
object IntMonoid : Monoid<Int> {
override val zero = 0
override operator fun Int.plus(other: Int) = this + other
}
context(Monoid<T>)
fun List<T>.sum() = fold(zero) { acc, t -> acc + t }
//Multi-with can help here if you want a lot of monoids
fun main() = with(IntMonoid) {
println(list(1, 2, 42).sum())
}
Uberto Barbini
05/04/2023, 9:57 AMIntMonoid
where comes from?Youssef Shoaib [MOD]
05/04/2023, 9:57 AMUberto Barbini
05/04/2023, 9:59 AMYoussef Shoaib [MOD]
05/04/2023, 10:00 AMIntSummable: Summable<Int>
to IntMonoid: Monoid<Int>
Uberto Barbini
05/04/2023, 10:01 AMUberto Barbini
05/04/2023, 10:01 AMUberto Barbini
05/04/2023, 10:01 AMUberto Barbini
05/04/2023, 10:01 AMUberto Barbini
05/04/2023, 10:08 AMinterface Monoid<T> {
val zero: T
operator fun T.plus(other: T): T
}
object IntMonoid : Monoid<Int> {
override val zero = 0
override operator fun Int.plus(other: Int) = this + other
}
context(Monoid<T>)
fun <T> List<T>.sum() = fold(zero) { acc, t -> acc + t }
//Multi-with can help here if you want a lot of monoids
fun main() = with(IntMonoid) {
println(listOf(1, 2, 42).sum().toString())
}
there were a couple of typos, this version compileUberto Barbini
05/05/2023, 6:20 AMinterface Monoid<T> {
val zero: T
operator fun T.plus(other: T): T
fun List<T>.monoidSum() = fold(zero) { acc, t -> acc + t }
}
//Int
object IntMonoid : Monoid<Int> {
override val zero = 0
override operator fun Int.plus(other: Int) = this + other
}
it works directly without any need of context receiver:
fun main() {
println(
listOf(1, 2, 42).monoidSum().toString()
)
}
Uberto Barbini
05/05/2023, 6:25 AMfun <T: exists Monoid<T>> reduce(l: List<T>): T = l.monoidSum()