5 ms·
> In particular, nullable types seem like a good idea (I thought so as well) but in practice are a real PITA. That's most acute when defining fields, where non-
by snuxoll 10y ago
> In particular, nullable types seem like a good idea (I thought so as well) but in practice are a real PITA. That's most acute when defining fields, where non-nullable fields have to be initialized directly.
> JetBrains themselves realized it was painful, and so we have `lateinit` to define mutable non-nullable fields that can be initialized later. But sometimes it really is nice to be able to check if a field has already been initialized, which you can't do here.
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.
- dimillian 10y agoJSON and reflection, you know you gonna get a value once you'll have instantiated your object from a JSON description. So my var are lateninit because I don't need a ? or !!
- snuxoll 10y agoInitialize them with default values, then? Or if you're using Jackson there is a module from FasterXML that provides support for Kotlin data classes. lateinit is a crutch to get things working, not something you want to use long-term.
- dimillian 10y agoNever really thought about it, didn't even realise it was tied to Jetbrain and not build into Kotlin itself. I feel initialise a default value counter intuitive, what the default of a string , "", "default", "test". I know it works because it'll be reassigned with the JSON value later, but still feel dirty. I prefer the Swift way let value: String!
- nostrademons 10y agoWhy not use Jackson? 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.
- afastow 10y agoLateinit is good for what it is designed for which is allowing for fields that are always going to be initialized before use but after construction, normally by a library. I wouldn't describe it as a crutch in that case. 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.
- snuxoll 10y ago> 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.
- vbezhenar 10y agolateinit is bad, because it forces you to use var. If you're using var, you can change this value later and you want the language to prevent that (unless you want a mutable property, of course).
- deleted 10y ago[deleted]
- lenkite 10y agoYou can use constructors for JSON now. See https://github.com/FasterXML/jackson-module-kotlin https://github.com/FasterXML/jackson-module-kotlin
- relics443 10y agoI use it a lot in Android, where certain objects are created by the framework, and I don't want a nullable reference for one of its properties.
- hota_mazi 10y ago> I'm curious, where have you found the need for lateinit? 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.
- snuxoll 10y ago> Android, JavaEE, web servlet containers, DI frameworks, etc... Most of which support constructor injection.
- hota_mazi 10y agoEr... none of them except maybe Guice? They all require a parameterless constructor so they can instantiate your objects before reflecting them.
- mejari 10y agoExactly. I spent some time testing out converting a small part of our large codebase that uses Spring to Kotlin and was able to easily switch over to constructor injection. I think it actually made the injection cleaner. It was nicer for my tests too, instead of @Mock/@InjectMocks magic.
- weitzj 10y agoIf you use Android along with dependency injection (Dagger2). This was at least necessary when Kotlin was close to 1.0. This was the only part where I ever used lateinit.
- snuxoll 10y agoDagger supports constructor injection, why would lateinit be necessary?
- dpkirchner 10y agoMany of the classes you'd write as an Android developer are instantiated by the system somewhere using only those constructors that the system expects to exist. Views, for example, are typically instantiated based on XML layout files that simply reference views by name, without a way to specify a specific constructor to use.
- snuxoll 10y agoAh, yes - layout inflation is such fun. Still, there are libraries you can use that don't require usage of lateinit. Kotterknife [1] is an option, the Kotlin android extensions [2] is another option though relying on code generation it may not be the first choice of people. Delegates in Kotlin are a powerful tool, and a great way to handle cases where you think lateinit is necessary but really isn't. 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 https://github.com/JakeWharton/kotterknife [2]: https://kotlinlang.org/docs/tutorials/android-plugin.html https://kotlinlang.org/docs/tutorials/android-plugin.html [3]: https://github.com/Kotlin/anko https://github.com/Kotlin/anko [4]: https://github.com/BennyWang/KBinding https://github.com/BennyWang/KBinding
- dpkirchner 10y agoI haven't seriously tried Kotterknife, anko (been meaning to!), or KBinding (hadn't heard of it before, will check it out) -- I'm currently enjoying the Kotlin android extensions for referencing views inside custom viewgroups. 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/39dda1965ee29740cab2e95c3930d968855f1f8b https://github.com/dpkirchner/kotterknife/commit/39dda1965ee...