Youssef Shoaib [MOD]
08/19/2020, 9:32 PMtginiotis
08/20/2020, 7:33 AMthanerian
08/20/2020, 7:36 AMthanerian
08/20/2020, 7:36 AMsimon.vergauwen
08/20/2020, 8:28 AMraulraja
08/20/2020, 11:22 AMYoussef Shoaib [MOD]
08/22/2020, 10:19 AMraulraja
08/22/2020, 2:27 PMraulraja
08/22/2020, 2:28 PMraulraja
08/22/2020, 2:31 PMraulraja
08/22/2020, 2:32 PMYoussef Shoaib [MOD]
08/22/2020, 10:22 PMYoussef Shoaib [MOD]
08/22/2020, 10:23 PMYoussef Shoaib [MOD]
08/22/2020, 10:26 PM(Boolean, T?) -> T?
lambda where the Boolean just denotes a branch for whether this is a get or set (this would also be accompanied by a simple inline factory method that has 2 crossinline parameters for the getter and the setter that just calls the getter if the boolean is true and calls the setter if it isn't. This inline class would then just be used as a property delegate (with the appropriate inline getValue
and setValue
operators that just return that same inline class and perform the setting operation respectively), but then there would also be the appropriate @Coercion
suspend functions that coerce that inline class into its type param (i.e. by calling its lambda with true) and also another coercion that coerces any arbitrary T
into an inline class of that T
(this is the only part where I'm not entirely sure whether or not it would be supported by the proofs plugin, but I think that it should hopefully work).Youssef Shoaib [MOD]
08/22/2020, 10:34 PM// Probably should use Optional for a lot of these nullables, but just as a PoC I'll use nullables
inline class SuspendProperty<T> internal constructor(internal val lambdaOrValue: Union2<suspend (Boolean, T?) -> T?, T>) {
// Impl details
operator fun getValue(...) = this
operator fun setValue(..., value) {
val lambda: (suspend (Boolean, T?) -> T?)? = lambdaOrValue
val actualValue: T? = value.lambdaOrValue
lambda?.invoke(false, actualValue)
}
}
fun <T> suspendProperty(getter: suspend () -> T, setter: suspend (T) -> Unit): SuspendProperty<T> =
SuspendProperty { isGet, value ->
if(isGet) getter()
else {
setter(value!!)
null
}
}
Then with these Coercions:
//Probably should also use a totally different datatype other than the delegate itself for this, but eh whatever
@Coercion suspend fun <T> SuspendProperty<T>.value(): T {
val lambda: (suspend (Boolean, T?) -> T?)? = lambdaOrValue
return lambda!!.invoke(true, null)!!
}
@Coercion suspend fun <T> T.toSuspendProperty(): SuspendProperty<T> = SuspendProperty(this)
The use site would look completely natural:
class Example {
var someRemoteString by suspendProperty(
getter = { TODO("Remote request for the string"),
setter = { TODO("Send the new value to the server or something) }
}
fun main() {
runBlocking {
val example = Example()
val str: String = example.someRemoteString
example.someRemoteString = str + ", or is it?"
funThatHasAStringParameter(example.someRemoteString)
}
}
Youssef Shoaib [MOD]
08/22/2020, 11:15 PMYoussef Shoaib [MOD]
08/22/2020, 11:17 PMgetXXXSuspend
and setXXXSuspend
), and then just replace every call to an accessor of the property with one of these functions and giving the user an error if it was called in a non-suspending context (basically the same as a regular function), but the proofs plugin really does make this easier albeit in a slightly convoluted way.raulraja
08/23/2020, 3:20 PMYoussef Shoaib [MOD]
08/23/2020, 4:19 PM