I'm curious, where have you found the need for lateinit? Forcing initialization of non-nullable types has always seemed like a great idea to me, and learning to deal with it in Kotlin has made picking up Rust a lot easier.
I'm curious, where have you found the need for lateinit? Forcing initialization of non-nullable types has always seemed like a great idea to me, and learning to deal with it in Kotlin has made picking up Rust a lot easier.
lateinit is a crutch to get things working, not something you want to use long-term.
I define the bulk of my JSON datatypes as:
data class Foo(
val bar: String,
val baz: String,
val quux: Int
)
No nullables needed, unless the actual JSON spec calls for a nullable field, in which case I want the compiler to remind me to handle the null case. Jackson handles everything out-of-the-box; it has no problem with constructor injection, and requires no annotations for the default case.For circular structures & injected values, I make them 'var' and inject after construction. This is a bit icky but generally manageable; if I get too uncomfortable with it, I can move the property declaration to the body, make it private set, and provide an accessor to handle all the injection at once.
It'd be ideal if libraries were better about using constructor injection when possible, but I think there are some valid scenarios where circular dependencies make it impossible to use only constructor injection.
Thankfully it is rare to require circular dependencies, but this is probably the one use case where lateinit is certainly warranted.
It's useful as soon as a field is managed by a container, which means it will most likely not be initialized at construction time of the object.
Examples of containers: Android, JavaEE, web servlet containers, DI frameworks, etc...
So basically, they are pretty much ubiquitous.
Most of which support constructor injection.
This was the only part where I ever used lateinit.
Otherwise, if you're going with Kotlin anyway you can just get rid of layout XML altogether with anko [3] or even give MVVM a shot with KBinding [4].
[1]: https://github.com/JakeWharton/kotterknife [2]: https://kotlinlang.org/docs/tutorials/android-plugin.html [3]: https://github.com/Kotlin/anko [4]: https://github.com/BennyWang/KBinding
I use field injection to pull in instantiated Picasso/Glide image libraries and to create/bind to persistent view presenters (it's a Mortar/Flow based app currently). I'm not sure if this is best practice or what but I feel reasonably comfortable having image loaders in the view (when those image loaders do their real work off the UI thread of course).
Speaking of Kotterknife, I'm actually in the process of migrating away from Butterknife as I slowly port the app over to Kotlin. Butterknife is immensely useful for Java-based apps, IMO, but the Kotlin android extensions provide most of what I need and Kotlin's syntax largely takes care of the boilerplate I was avoiding by going with BK in the first place. I do miss string/integer/other binding but it's not so bad and, IIRC, kotterknife doesn't provide that anyway -- I explored adding it [1] but I didn't enjoy writing all that code and ended up giving up.
I forgot to mention another use-case for lateinit: junit tests. I use lateinit in the test class when testing code that uses constructor injection. This is probably less controversial because it is just tests, though.
[1] https://github.com/dpkirchner/kotterknife/commit/39dda1965ee...