what is the best way to set an initial value for g...
# getting-started
m
what is the best way to set an initial value for generic type since you cant mark it as lateinit and making it nullable making it non-correct (ie user want it as non nullable)? I see some null-surrogate logic in
StateFlowImpl
by using
Symbol
(LoC in context) but its an internal coroutines API and marked as an unstable API
Copy code
private var _value: T = // need to set default value here but can't be null

override var value: T
    get() = _value
    set(value) {
        if (disabled) throw IllegalStateException("Can not set value to $value as bindable is disabled.")

        if (value?.equals(_value) == true) return
        setValue(_value, value)
    }
j
Does your generic type
T
accept nullable types? (meaning, can the user use nullable types as
T
/ does it make sense in your case?)
m
T
accept nullable, yes
j
Then why is
value?.equals(_value)
a valid test? It seems the user will not be able to set
null
in this case. If you already don't allow users to set null, you could forbid it entirely by adding the
: Any
bound to your
T
, and then use the
T?
type for your backing field, and null as your default value (or use lateinit)
The question is a bit strange to me, because the initial value depends on your use case. If the type weren't generic, what would be the difference? You might need to get the default from the user depending on what your code is doing
If this makes sense in your case, another solution could be to use a sealed class like this:
Copy code
sealed class MyValue<out T> {
    data object Unset : MyValue<Nothing>()
    data class Set<T>(val value: T): MyValue<T>()
}
But that might be quite overkill depending on what your use case is
m
value?.equals(_value)
is just me trying to skip the
setValue
if the new value is the same as current value.
You might need to get the default from the user depending on what your code is doing
aha so it implies that end user should set the initial value instead?
j
I don't know, because I don't know the broader picture. What is this code about?
> value?.equals(_value) is just me trying to skip the setValue if the new value is the same as current value Is also skips if the user tries to set
null
. Why not use
value == _value
?
m
so my goal is let user create the object without needing to specify the default value (it also mean user still can provide default value via non-primary constructor and set the
_value
from start), and the next goal is throwing an exception if user try to query the value when it's not initialized. I initially set the
_value
as null, but it also implies the
T
is "always" nullable since
value
will become
T?
. sounds a bit weird usecase sure but I'm trying to make it looks same as the original API I tried to port here. so yeah tl;dr is basically i want to set default value of
T
"internally" without needing user to set the value. full code for more context.
also yeah, just read equality docs,
value == _value
should be used here. need to cover more on my test.
j
> but it also implies the T is "always" nullable since value will become T?. No, only
_value
becomes
T?
, but
value
can stay
T
if you write the getter to fail when
_value
is null (access to uninitialized value). But indeed that means you can no longer support null as a valid value for users. So, in short: • if you don't need to support null as a valid value for users, just add a non-nullable bound on
T
with
T : Any
, and use lateinit. • if you do need to support null as a valid value for users, keep your
T
general like this, but use a sealed class as shown above to represent the uninitialized value. If you're worried about the performance of the sealed class, you could also choose to use an unsafe
Any?
type for
_value
, use an arbitrary object to represent your uninitialized value, and use unsafe casts locally (hidden in your getter/setter).
👍 1
m
will try the later and see how it goes. thank you