https://kotlinlang.org logo
Title
j

Jakub Komorowski

09/27/2019, 12:13 PM
Hello, fellow Kotliners! Recently I’ve came across a following problem. I was implementing a custom Android view, and the base View I was extending had
setEnabled
method. I’ve overridden it in my class, and used properties from the child class in this overwrite. As the properties I’ve used were unmutable and non-nullable I was startled when my app crashed with
NullPointerException
thrown in that method. Turns out it was called from the superclass constructor, and properties are initialized only after superclass constructor call. The simplified code that caused my problem looks something like: https://bit.ly/2n6xmm5 . When you run it, it throws
NullPointerException
when using seemingluynon-nullable property. Is there a pattern that would allow us to omit method calls on unitialized unmutable properties? I found two solutions to that problem, but I don’t think they’re very elegant. One using lateinit vars https://bit.ly/2nPYBBX - pretty ugly, and one using a flag https://bit.ly/2mgG4hq - pretty weird. All of the urls are shortened https://play.kotlinlang.org code snippets.
i

Iaroslav Postovalov

09/27/2019, 12:25 PM
there's #android channel...😑
j

Jakub Komorowski

09/27/2019, 12:27 PM
@Iaroslav Postovalov Thank you for letting me know, but it’s a language issue, not an Android one. I wanted to know if there’s a way in which I could check if my property was already initialized when I want to call it.
i

Iaroslav Postovalov

09/27/2019, 12:30 PM
@Jakub Komorowski either reflection or storing nullable (or Optional, if null is valid value too)
j

Jakub Komorowski

09/27/2019, 12:50 PM
@Iaroslav Postovalov In case null values are not valid, how I would go about this using reflections? The only method I know of (’`isInitialized` property) can only be used for
lateinit
properties, and, as can be seen in the snippet I provided, converting properties to those looks pretty ugly.
s

streetsofboston

09/27/2019, 1:14 PM
Using
isInitialized
is usually a code-smell. Use it very sparingly.. Either use nullable types
?
or use the
by lazy { .... }
(and provide the right dependencies for the code in the lazy-block to work).
j

Jakub Komorowski

09/27/2019, 1:19 PM
@streetsofboston Sadly, lazy intialization doesn’t work in that case, I’m not entirely sure why: https://play.kotlinlang.org/?_ga=2.112366796.93175216.1568720306-1499155423.1536137988#eyJ2ZXJzaW9uIjoiMS4zLjExIiwicGxhdGZvcm0iOiJqYXZhIiwiYXJncyI6IiIsImpzQ29kZSI6IiIsIm5vbmVNYXJrZXJzIjp0cnVlLCJ0aGVtZSI6ImlkZWEiLCJmb2xkZWRCdXR0b24iOnRydWUsInJlYWRPbmx5IjpmYWxzZSwiY29kZSI6ImZ1biBtYWluKGFyZ3M6IEFycmF5PFN0cmluZz4pIHtcbiAgIHZhbCBkZXJpdmVkID0gRGVyaXZlZFZpZXcodHJ1ZSlcbiAgIGRlcml2ZWQuc2V0RW5hYmxlZCh0cnVlKVxufVxuXG5vcGVuIGNsYXNzIEJhc2VWaWV3KGlzRW5hYmxlZDogQm9vbGVhbikge1xuICAgIGluaXQge1xuICAgICAgICBzZXRFbmFibGVkKGlzRW5hYmxlZClcbiAgICB9XG4gICAgXG4gICAgb3BlbiBmdW4gc2V0RW5hYmxlZChpc0VuYWJsZWQ6IEJvb2xlYW4pIHtcbiAgICAgICAgcHJpbnRsbihcIkJhc2VcIilcbiAgICB9XG59XG5cbmNsYXNzIERlcml2ZWRWaWV3KGlzRW5hYmxlZDogQm9vbGVhbikgOiBCYXNlVmlldyhpc0VuYWJsZWQpIHtcbiAgICBwcml2YXRlIHZhbCBlbmFibGVkQmFja2dyb3VuZDogRHJhd2FibGUgYnkgbGF6eSB7IERyYXdhYmxlKFwiZW5hYmxlZEJhY2tncm91bmREcmF3YWJsZVwiKSB9XG4gICAgcHJpdmF0ZSB2YWwgZGlzYWJsZWRCYWNrZ3JvdW5kOiBEcmF3YWJsZSBieSBsYXp5IHsgRHJhd2FibGUoXCJkaXNhYmxlZEJhY2tncm91bmREcmF3YWJsZVwiKSB9XG4gICAgXG4gICAgb3ZlcnJpZGUgZnVuIHNldEVuYWJsZWQoaXNFbmFibGVkOiBCb29sZWFuKSB7XG4gICAgICAgIHN1cGVyLnNldEVuYWJsZWQoaXNFbmFibGVkKVxuICAgICAgICBcbiAgICBcdHNldEJhY2tncm91bmQoaWYoaXNFbmFibGVkKWVuYWJsZWRCYWNrZ3JvdW5kIGVsc2UgZGlzYWJsZWRCYWNrZ3JvdW5kKSAgICAgICAgXG4gICAgfVxuICAgIFxuICAgIHByaXZhdGUgZnVuIHNldEJhY2tncm91bmQoYmFja2dyb3VuZDogRHJhd2FibGUpIHtcbiAgICAgICBcdHByaW50bG4oXCJCYWNrZ3JvdW5kIHNldCB0byAke2JhY2tncm91bmQubmFtZX1cIilcbiAgICB9XG59XG5cbmRhdGEgY2xhc3MgRHJhd2FibGUodmFsIG5hbWU6IFN0cmluZykifQ== Nullable types are viable solution, but that creates the need to use safe calls, or non-null assertion operator in non-overriding methods.
s

streetsofboston

09/27/2019, 1:28 PM
Because you call
setEnabled(isEnabled)
in the constructor of the base-class
BaseView
. The sub-class
DerivedView
has not yet been instantiated at all.
j

Jakub Komorowski

09/27/2019, 1:30 PM
Yes, hence my question. Of course, if I had control over the base class I could change it, but when working with existing code, such as Android view classes, I can’t really do that.
d

Dico

09/27/2019, 5:06 PM
You can also just add
val initialized = true

override fun setEnabled(...) {
   super.setEnabled...
   if (initialized)...