The danger of assumptions: Kotlin with Android custom views

Exploring the wonders that Kotlin offers for Android developers I came across a nice language feature that can simplify and improve…

The danger of assumptions: Kotlin with Android custom views

Exploring the wonders that Kotlin offers for Android developers I came across a nice language feature that can simplify and improve readability of my code: constructors with default arguments 😍

I won’t go too much into detail (there are articles about it) but the summary is that instead of writing this kind of constructors for Android custom views:

Now you can (but you shouldn’t) write this:

This calls the longest form of the parent View constructor with a combination of passed values and default values for each missing argument.

This code runs, but it makes a couple of assumptions that won’t make your app crash, instead, they will make your views behave incorrectly (wrong sizes, font, etc.) and can lead to time-consuming hair-pulling debugging sessions 😰

Assumption 1: Default values

The first time I used this technique it worked because the defaults I used in MyCustomView (null and 0) aligned with what the parent View class uses.

The problem starts to manifest when the parent class uses other defaults, here are the defaults for the second constructor in the Android Toolbar class:

I can workaround this by simply copying the defaults from this Android class to MyCustomView, and use R.attr.toolbarStyle instead of 0

The problem with this workaround is that it assumes the Android class will not change the default value for the style attribute, ever 😅

Assumption 2: Constructor call chain

The short Kotlin constructor skips all intermediate constructors in the parent View. This is a more subtle problem but it can prove dangerous when we use this technique to call a parent class constructor that doesn’t belong to us.

I’m assuming that all constructors in the Android Java class simply call each other without extra logic until the longest one with all arguments is called (see the Toolbar Java constructor calling this). But Google didn’t promise to do this with all Android Views and consistently across all Android versions.

Imagine this code is released with the next version of Android X:

Now MyCustomView class is completely missing the new logic and method call implemented in the Android class because I was assuming Google would never change the behavior of the constructors.

Conclusion

Avoid writing methods with default arguments in Kotlin if your method is calling an overloaded method that does not belong to your code. It is a simple and safe solution to stop making assumptions about libraries and frameworks we don’t control.

Happy coding 🖖


Check out our Engineering Blog for more in depth stories on pragmatic code for happy users!