What's the best way to memoize the result of a delegated property when using `val x by delegate`? I...
r
What's the best way to memoize the result of a delegated property when using
val x by delegate
? I could stick it in a cache in the Delegate class, but wondering if there's a simpler way... I suppose I could wrap it in a lazy, but I'd rather it was eagerly evaluated. I'm really only using it for syntax sugar to reduce boilerplate.
s
If it’s both eagerly evaluated and memoized, is that different from just initializing it normally, without a delegate?
r
Context - creating classes representing database tables. They currently look like this:
Copy code
class UserTable(dialect: SQLDialect) : DbTable(dialect, "USERS") {
  val USER_ID = fieldFor("USER_ID", Long::class.java)
}
and I'm using a delegate to reduce that to:
Copy code
class UserTable(dialect: SQLDialect) : DbTable(dialect, "USERS") {
  val USER_ID by field<Long>()
}
s
Gotcha, so really the property delegate is just there to grab the property name 👍
r
Exactly
The
fieldFor
method actually mutates the state of the class, so I'm getting a lot of fields called
USER_ID
at the moment because everytime
USER_ID
is called a new field is created.
s
🤔 the
field<Long>()
method should only be called once, when the property is created. What’s your implementation of that method?
r
Untitled.kt
s
I think the problem you’re going to have is that you want the property name in order to create the value, and you want to create the value eagerly when the property is declared, but the property delegate only gives you the property name at the point when the property is accessed, not when it’s initialized.
As in, you ideally want the property name in the initial call to
field
, but you actually only get it inside the call to
getValue
I think you can solve it with a property delegate provider, please hold
v
but the property delegate only gives you the property name at the point when the property is accessed, not when it’s initialized.
You can probably use
provideDelegate
to change that
☝️ 1
That should only be called once when initializing the delegated property
s
Copy code
val USER_ID by field<Long>()

private inline fun <reified T> field() =
    PropertyDelegateProvider<Any, ReadOnlyProperty<Any, T>> { _, property ->
        val value = fieldFor(property.name, T::class.java)
        ReadOnlyProperty { _,_ -> value }
    }
Something like that 🤷
r
Awesome, thanks both - will have a play
For anyone following along at home
😁 1
Actually the compiler didn't catch it but needed an
@PublishedApi internal fun
Untitled.kt