Breaking Kotlin's Null-Safety with Circular References
Circular object references can be dangerous. They break code at runtime, and are difficult to guard against at compile time.
Consider the following example:
Although innocuous at first glance, this code breaks Kotlin’s non-nullable types.
If you run this example on Kotlin Playground, it produces the following output:
null value snuck into a non-nullable type.
objects are lazily initialized1.
LewisHamilton gets initialized upon its first-access in
main. Its constructor references another lazy variable
Mercedes, whose constructor has a circular reference to
Therefore, constructor of
Mercedes references a yet-uninitialized
LewisHamilton variable, and leads to a null value being stored in a non-nullable variable.
While this is bug is easy to fix, the problem is that this code fails at runtime, thus silently breaking Kotlin’s non-null types.
Consider starring this issue to get more attention to this problem: KT-44633: Circular object references silently break Kotlin’s non-nullable types
More Circular Reference Madness
Let’s look at a few more examples to illustrate problems with circular references.
This code produces a
StackoverflowError. You can try it here.
Foo is a data class, its
toString() implementation calls the same method on its member properties too. This leads to an ever growing call-stack.
A simpler, more condensed version of the same problem can be illustrated as follows:
This code again produces a
CircularRef.toString() continues recursing forever. Try it here.
Not just Kotlin
The problem of Circular References plagues other languages too. Here’s an example of the same code in Go.
Note circular references in the
String() method on both interfaces. Run this here.
This code never prints Finished. While the execution timeout on play.golang.org prevents this code from running for long, the same code on my local machine prints:
fatal error: stack overflow.
Be on the look out for circular references in your Kotlin code. You will receive no compile time errors or warnings about them.
If you would like to change that, consider starring this issue: KT-44634: Circular object references silently break Kotlin’s non-nullable types.
Thanks to Subhrajyoti Sen for reviewing this post!
Question, comments or feedback? Feel free to reach out to me on Twitter @haroldadmin