Hello, is it possible to have by lazy property whi...
# announcements
a
Hello, is it possible to have by lazy property which calls suspend function for a value? Eg
Copy code
val context by lazy { contextProvider() }
where contextProvider() is suspend function
d
That would require the getter for
context
to be
suspend
as well. Since suspend getters / setters aren't supported yet this is not possible
a
understood
maybe, for alternative there is some function memoization mechanism inside kotlin sdk?
Problem is that I had source where only one place required call to contextProvider() which is expensive
and now there are couple places where contextProvider's value are needed
g
Just use async for this, it has almost the same semantics, just use await() instead of direct property access
a
I wish to write something as: val contextProviderFun = memoized {contextProvider() }
contextProviderFun()
g
Copy code
val context = async(start = Lazy) { contextProvider() }
a
!
legit 🙂
thanks!
g
To get result use it directly; context.await()
a
I do not know is this semantics is not too advanced, but will work in my case
g
Or abstract with some suspend function
a
:))
could be some
memo
inline fun inside kotlin sdk for that
g
Like: suspend fun context() = context.await()
And how would this memo work? Looks exactly as existing Lazy
a
g
How is that different from lazy?
a
Lazy do not allow suspend functions
just by that
g
I mean memoize is not hard, but you still need a place to keep instance of this function
Than async!
I don't see in docs that this memoize from lodash is asyncronous
a
it will do the same, but actually concepts is not the same, Memoization
g
Why not the same?
a
no, but in general, memoization - is storing computed value by function and not calling function again if arguments is the same
async - is async
😄
g
This is exactly what async does
You can create own coroutine builder with name memoize
a
to be precise async uses memoization
but it's not memoization
g
🤔
I mean memoization itself is easy
But if you add asyncronous background job to it become not so easy at all
a
g
I know what is memoization
a
oh, you mean that in async context
memoization is not memoization by definition
but from a callers perspective there should be no worry if it's async or not with suspend functions
just must be called inside some coroutine context
g
It's not so easy, it would be against structured concurrency, because you always should be explicit about scope and pure suspend function will not work
a
wait I'll write a little example of how I'm imagining this
Copy code
suspend fun <R>memoize(block: suspend () -> R): () -> R {
    val Undef = object {}
    var value: Any = Undef
    return {
        if (value === Undef) value = block()
        value
    }
}
g
Yeah, you can do this like that
a
Copy code
suspend fun context() = memoize {
    contextProvider()
}
g
yes
a
problem that i cannot call block()
inside return { }
because it's not suspend lambda
😕
g
you can
return suspend { }
a
Copy code
suspend fun <R> memoize(block: suspend () -> R): suspend () -> Any {
    val Undef = object {}
    var value: Any = Undef
    return suspend {
        if (value === Undef) value = block() as Any
        value
    }
}
seems this is ok
but it's only for zero argument functions
g
you can just create N overrides for different arguments
a
and it not looks complicated as it will execute everything on the same coroutine
but it could be inside kotlin std
g
why complicated and what is problem with the same coroutine
I don’t think that it really worth to add to stdlib
but if you think it’s useful, just create own library
a
I think Arrow library should have these
g
Yes, probably
Funktionale had it
a
Copy code
suspend fun <R> (suspend () -> R).memoize(): suspend () -> Any {
    val Undef = object {}
    var value: Any = Undef
    return suspend {
        if (value === Undef) value = this() as Any
        value
    }
}
and it could be extension function on any function (maybe too much)
this() as Any
Is invalid. R may be null
a
oh, shoud be "Any?" yes?
these implementations (Funktionale,Arrow) are not suspend friendly
Copy code
suspend inline fun <R> (suspend () -> R).memoize(): suspend () -> R {
    val Undef = object {}
    var value: Any? = Undef
    return suspend {
        if (value === Undef) value = this() as Any?
        value as R
    }
}
and usage:
Copy code
val lazyContextProvider = contextProvider.memoize()
/// ...
val context = lazyContextProvider()
b
why can't you use runBlocking block in lazy property initializer block?
Copy code
val context by lazy { runBlocking{ contextProvider() } }
g
Yes, it should be
Any?
Oh, it’s blocks the thread! I don’t think that it’s expected behavior
b
I think the OPs issue is that he needs to retreive the data from suspend function, which requires coroutine scope. Not an async lazy property
g
You don’t need coroutine scope to call suspend function, you need suspend lambda Anyway. block thread just make coroutines useless in this case. It can be valid in some cases, but always should be explicit
these implementations (Funktionale,Arrow) are not suspend friendly
@Antanas A. Yes, I know, there is no way to make them suspend friendly, only by generating suspend version of them, If you use Arrow, you can create a feature requests about it
a
We're using runBlocking only in tests and in integration with legacy (thread based) libraries
No, for us, the Arrow is too advanced today :))
as team is currently only in OOP thinking
d
suspend operator fun getValue(...)
is invalid?
I guess so