elect
10/02/2021, 10:40 AMval username by Input { }
Where
class Input {
companion object {
operator fun invoke(..): Input {
..
}
}
}
And
internal operator fun Any.getValue(thisRef: Any?, property: KProperty<*>): Input {
println("$thisRef, thank you for delegating '${property.name}' to me!")
val pInput = property as KProperty0<Input>
println(pInput)
return pInput.get()
}
pInput
is a valid KProperty0
class, but the moment I call .get()
to retrieve Input
, then I get:
java.lang.UnsupportedOperationException: call/callBy are not supported for this declaration.Why? How can I fix it? What is the way to retrieve the
Input
instance produced by its own companion object?Joffrey
10/02/2021, 10:51 AMinvoke
on the companion instead of just using a constructor?Joffrey
10/02/2021, 10:53 AMgetValue
declared here? Inside the Input
class or at the top level?elect
10/02/2021, 10:53 AMelect
10/02/2021, 10:55 AMInput
Joffrey
10/02/2021, 10:55 AMAny
?elect
10/02/2021, 10:56 AMusername
) as well and use it to create Input
(it's one of the fields)Joffrey
10/02/2021, 10:58 AMusername
so the delegate is the one that's supposed to provide the valueJoffrey
10/02/2021, 10:59 AMelect
10/02/2021, 11:00 AMelect
10/02/2021, 11:00 AMclass Input {
fun getValue(..)
}
?elect
10/02/2021, 11:00 AMinvoke
) is actually providing the value, or am I wrong?elect
10/02/2021, 11:03 AMAny
so that I can also have type inferenceJoffrey
10/02/2021, 11:51 AMInput
to be the type of the delegate but you also want it to be the type of the value? I cannot really suggest anything at the moment because I didn't get what you're trying to do. What is the purpose of the delegate?elect
10/02/2021, 11:54 AMusername: Input
in the lambda, this should include saving the variable name itself, that is username
inside the Input
instance itselfelect
10/02/2021, 11:56 AMval task by tasks.creating { }
Joffrey
10/02/2021, 12:06 PMval username = Input { ... }
elect
10/02/2021, 12:07 PMusername
from inside Input{..}
in that wayelect
10/02/2021, 12:08 PMusername
is Input.id
elect
10/02/2021, 12:13 PMclass Delegate(val block: Input.() -> Unit) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Input {
println("$thisRef, thank you for delegating '${property.name}' to me!")
return Input().apply {
block()
id = property.name
}
}
}
Joffrey
10/02/2021, 12:15 PMInput
type. The code you provided last can work, but then you'll create a new instance of Input
every time you access username
. You can use the provideDelegate
approach in order to store the value and return the same one everytime it's accessedelect
10/02/2021, 12:17 PMelect
10/02/2021, 12:17 PMprovideDelegate
approach?elect
10/02/2021, 12:19 PMJoffrey
10/02/2021, 12:20 PMprovideDelegate
function is called once when the class containing the delegated property is initialized. This function creates an instance of the delegate class and you already have access to the property name when doing so, so you can store the value in the delegate instance itselfJoffrey
10/02/2021, 12:45 PMJoffrey
10/02/2021, 12:47 PMelect
10/02/2021, 4:44 PMelect
10/02/2021, 4:44 PMby
won't save the value in the variable by default, like by lazy
, instead of requiring all this boilerplate code, but anywayelect
10/02/2021, 4:52 PMOne of the possible use cases ofis to check the consistency of the property upon its initialization.provideDelegate
elect
10/02/2021, 5:04 PMelect
10/02/2021, 5:06 PMPropertyDelegateProvider
(at the end of the same doc link posted above)
I guess no, because there isn't a way to pass the lambdaJoffrey
10/02/2021, 6:23 PMPropertyDelegateProvider
and never thought of using SAM conversions like this!
It is definitely possible to use by capturing the configure
lambda (and it would simplify the whole thing quite a bit):
private fun Input(configure: Input.() -> Unit) = PropertyDelegateProvider { thisRef: Any?, prop ->
val input = Input(prop.name).apply { configure() }
ReadOnlyProperty<Any?, Input> { _, _ -> input }
}
So the whole thing is now: https://pl.kotl.in/n6KFhfDOp
Thanks for making me learn this 🙂Joffrey
10/02/2021, 6:38 PMI still don't get why a planI don't get your point here. The implementation of the lazy delegate does need to store thewon't save the value in the variable by default, likeby
by lazy
value
explicitly, look:
https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/util/Lazy.kt#L95
However, they don't need the additional indirection of provideDelegate
because they don't need information about the property itself (like the name of the property), unlike in your use case.elect
10/02/2021, 6:47 PM