i need a 'resettable lazy' delegate, i've seen a f...
# announcements
b
the goal is to get a 'cached' variable where the cache can be invalidated (and the variable should have its initializer re-run)
s
Why not make it a nullable
var
instead?
b
pffft who wants to have to deal with null in kotlin? 🙂 plus i'd like to encapsulate the re-initialization logic
s
You can create a non-nullable (non lateinit) var, using a property Delegate.
b
and, the field is not actually nullable, it's a view of a field from a buffer and the buffer can change, but re-parsing it every time would be costly, i only want to re-parse when something has changed
yeah i just wanted something a little cleaner than explicitly making a call to re assign it
s
This means it has certain behavior: Create/parse the value, return the cached value, clear the cached value. Why not make your own class called
Cached<T : Any>
that caches values of type
T
, creates/parses it when it is not cached and allows the value to be cleared (cache-clear)?
b
yeah, that's the idea, i was just looking to do it as a delegate
ideally it'd be lazy as well
so there are some implementations to that i've found (in the links above), they're just a bit old...was just wondering if perhaps there was something cleaner now as they involve basically copying the
lazy
implementation and adding an
invalidate
s
That is possible: One part of the code will hold on to the property-delegate object, provide it to the class-instance that then uses this property-delegate. Then users of that class-instance can use the property as if it were a regular/plain property
But how would you call `invalidate`….?
b
yeah, the implementations above save a reference to the delegate type, which sucks. and getting the delegate from the field also kinda sucks
but how does your solution change that? if the property still has it's type, then i'll have to cast/get the delegate to call invalidate, no?
i was actually planning on passing a prop reference to the delegate that serves as the dirty flag
so the class just sets the boolean to true, and the delegate can check it's current value
rather than having to get the delegate and call
invalidate
s
Copy code
class CacheDelegate<T : Any>(private var initialValue: T? = null, private val factory: () -> T) {

    operator fun getValue(owner: Any, property: KProperty<*>) : T {
        if (initialValue == null) {
            initialValue = factory()
        }
        return initialValue!!
    }

    operator fun setValue(owner: Any, property: KProperty<*>, value : T)  {
        initialValue = value
    }
    
    fun invalidate() {
        initialValue = null
    }
}

class TestClass(
    testValueDel : CacheDelegate<Int>
)  {
    var testValue: Int by testValueDel
}

fun main() {
    val delegate = CacheDelegate {
        4
    }
    val testClass = TestClass(delegate)

    
    val x = testClass.testValue
    
    testClass.testValue = 234

    ...
    
    delegate.invalidate()
}
b
yeah i was thinking i'll just keep a
var dirtyFlag: Boolean
in
TestClass
and pass that as a property reference to
CacheDelegate
, so that way i can avoid a separate member for the delegate
still an extra member, but feels a little more natural
s
Depends.. It depends what part of your code is managing the caching of these values. In my example,
TestClass
doesn’t have to worry about invalidating caches, nor the code that uses the
TestClass
.
b
i think i'll end up with something like that, but it'll be a bit more complex as i want the cached field to be lazy as well
true, for my case it makes more sense for the class itself to manage
s
The
CacheDelegate
class here is lazy… 🙂 Ah.. yep, then just a simple boolean suffices; maybe add
get()
and
set(value)
for those properties …
b
ah, i do see now that it's lazy...i'm just a bit paranoid about it being as threadsafe as the built-in
lazy
so i guess i'll have to end up copying it and tweaking for the reset
actually, passing the prop reference makes resetting it a bit awkward...so i guess i will go with the
invalidate
method
241 Views