rad
03/11/2025, 4:37 PMgetValue
operators cannot be suspending due to them taking in a Continuation
. I also can't runBlocking
since that uses a new/different context. This is pretty much what I want to do:
public open operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {
val ctxElement = coroutineContext[CommandContextElement] ?: error("no command ctx element found")
val ctx = ctxElement.context ?: error("ctx is unset in ctx element")
return ctx.get<T>(id)
}
rad
03/11/2025, 4:41 PMYoussef Shoaib [MOD]
03/11/2025, 5:10 PMrad
03/11/2025, 6:09 PMThreadLocal
? I really want to keep the delegation-based syntax haharad
03/11/2025, 6:10 PMsuspend fun get(): T?
but meh, that's no funYoussef Shoaib [MOD]
03/11/2025, 6:11 PMsuspend
properties man.rad
03/11/2025, 6:15 PMThreadLocal
here or a function
context(CommandContext<Source>)
public open suspend fun value(): T? {
return get<T>(id)
}
This works for now 😔Youssef Shoaib [MOD]
03/11/2025, 6:35 PMrad
03/11/2025, 6:35 PMYoussef Shoaib [MOD]
03/11/2025, 6:36 PMYoussef Shoaib [MOD]
03/11/2025, 6:36 PMrad
03/11/2025, 6:39 PMrestoreThreadContext
where I would be setting my context element regularly and then call updateThreadContext
when I need to access it or how does this work?Youssef Shoaib [MOD]
03/11/2025, 6:48 PMwithContext
for your updates (if any)rad
03/15/2025, 1:16 PMCoroutineScope
context receiver would work, will try that once I'm back home 🤔rad
03/16/2025, 12:08 PMcontext(CommandBuilder) // Where I'm declaring the delegate
public open operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {
throw UnsupportedOperationException()
}
context(CommandExecutionContext) // Where I would like to use it
public open operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {
return ctx.get<T>(id) // ctx is from the execution context
}
This may seem a bit hacky, but you can achieve something similar if you have your second context receiver be a CoroutineScope
Youssef Shoaib [MOD]
03/16/2025, 12:24 PMCommandExecutionContext
at the declaration side, and won't actually be getting it at the call-side of the getterYoussef Shoaib [MOD]
03/16/2025, 12:27 PMimport kotlin.reflect.*
fun main() {
// Fails with
// Property delegate must have a 'getValue(Nothing?, KProperty0<String>)' method. None of the following functions is applicable: context(String) fun getValue(thisRef: Any?, property: KProperty<*>): String
//val foo by Foo
with("world") {
val foo by Foo
with("hi") {
println(foo) // prints "world"
}
}
}
object Foo {
context(String)
operator fun getValue(thisRef: Any?, property: KProperty<*>): String = this@String
}
rad
03/16/2025, 12:29 PMUnsupportedOperationException
, that's a bit annoyingYoussef Shoaib [MOD]
03/16/2025, 1:05 PMrad
03/16/2025, 1:07 PMYoussef Shoaib [MOD]
03/16/2025, 1:08 PMAt this point, properties with context parameters may not use delegation. It is unclear at this point what should be the correct semantics for such a declaration.
rad
03/16/2025, 1:17 PMrad
03/16/2025, 1:53 PMrad
03/16/2025, 2:24 PMpublic interface ArgumentAware {
public fun <T : Any> get(id: String): T?
public operator fun <T : Any> CommandArgument<T>.getValue(thisRef: Any?, property: KProperty<*>): T? {
return get<T>(id)
}
}
public class CommandBuilder : ArgumentAware {
override fun <T : Any> get(id: String): T? {
throw UnsupportedOperationException("Cannot get an argument in a command builder")
}
}
public interface CommandExecutionContext : ArgumentAware {
override fun <T : Any> get(id: String): T? {
...
}
}
This also does not work and just throws the UnsupportedOperationException
from the CommandBuilder...rad
03/16/2025, 2:36 PMYoussef Shoaib [MOD]
03/16/2025, 3:05 PMrad
03/16/2025, 3:54 PMYoussef Shoaib [MOD]
03/18/2025, 6:55 AMrad
03/19/2025, 7:31 PMkotlinx.coroutines.internal.intellij.IntellijCoroutines.currentThreadCoroutineContext
does seem very useful, I might use this instead, thanks!rad
03/20/2025, 3:38 PMpublic open operator fun getValue(thisRef: Any?, property: KProperty<*>): T? {
val coroutineContext = IntellijCoroutines.currentThreadCoroutineContext() ?: error("not in a coroutine")
val ctx = coroutineContext[CloudCommandExecutionContext] ?: error("no execution context found")
return ctx.ctx.get<T>(id)
}
This works, thanks!