https://kotlinlang.org logo
#getting-started
Title
# getting-started
m

Mark

11/12/2023, 4:33 AM
Suppose I have a private nullable var property. When a function is called, a check is made for whether the property is null. If so, the property is assigned a value. However, what is the idiomatic way to handle when null is a valid value? I know there are hacks, like to use a 1-length `List`/`Array` or use a JVM
AtomicReference
. But looking for a proper Kotlin way.
a

ascii

11/12/2023, 4:44 AM
You want to assign only if hasn't been initialized yet? Or if it was null specifically?
lateinit
would be a perfect fit for the former (but that doesn't allow nullable types), otherwise there's no Kotlin sugar involved. You'll have to use something else to denote an uninitialized state, e.g. Object/Any.
m

Mark

11/12/2023, 6:47 AM
Okay thanks. Strange there is no idiomatic way to do this. Must be quite common.
s

Sam

11/12/2023, 7:10 AM
This sounds a lot like lazy initialization, in which case you could use the
Lazy
delegate. For example:
Copy code
val x: X? by lazy { /* init on first use */ }
m

Mark

11/12/2023, 7:11 AM
unfortunately I can’t use lazy. I actually need a @Composable context to instantiate. For more background, I’m doing some text measurements.
👍 1
s

Sam

11/12/2023, 7:13 AM
I'd suggest
remember
instead of
lazy
but I'm sure you've considered that
m

Mark

11/12/2023, 7:15 AM
For more background, I’m writing something that will check the glyph metrics of a code point for a certain font. I do a one time calculation (measuring things like tofu metrics) in order to instantiate this checker. So you only want to do it once per JVM (per
FontFamily
)
Actually I store these checker instances in a
WeakHashMap
which doesn’t like null keys (which is what I would want for a null
FontFamily
. I suppose I could use a custom non-null key instead
e

efemoney

11/12/2023, 12:33 PM
> Strange there is no idiomatic way The kotlin way would be a sealed class.
Copy code
private sealed interface Prop {
  data object Uninitialized: Prop
  data class Initialized(val value: Actual?): Prop
}
👍 1
s

Stephan Schröder

11/12/2023, 2:08 PM
since this solution is only wrapping a single value, I'd use a value class:
Copy code
private sealed interface Prop {
  data object Uninitialized: Prop
  @JvmInline value class Initialized(val value: Actual?): Prop
}
the
@JvmInline
annotation is only necessary on a JVM backend.
👍 1
e

efemoney

11/12/2023, 2:36 PM
Yeah a value class makes sense but it would be stored as boxed (so no difference)
d

Daniel Pitts

11/12/2023, 4:04 PM
Any reason to not just assign it the default value initially?
c

CLOVIS

11/12/2023, 4:30 PM
since this solution is only wrapping a single value, I'd use a value class
Note that in this case it will always be boxed, because value classes are only inlined when used directly. If you declare the variable with an interface type, the class cannot be inlined.
e

ephemient

11/13/2023, 3:55 AM
For more background, I’m doing some text measurements.
there are non-null "uninitialized" values you can use.
Dp.Unspecified
for example
m

Mark

11/13/2023, 5:24 AM
Thanks, but in my case these text measurements are wrapped in a custom type. Also they are density independent.
e

ephemient

11/13/2023, 5:39 AM
Dp
is density-independent, it's pixels that are density-dependent. in any case, perhaps modify the type to include some sentinel values? many other Compose types do similar
m

Mark

11/13/2023, 7:15 AM
I guess it depends how you look at it. But anyway, I mean the instance will exhibit the same behavior regardless of
LocalDensity.current
value. Can be reused across densities etc. But yes, a single
object
representing
Unspecified
makes sense. There are no exposed properties, so it would just give dummy behavior.