Thanks to the advice of several tireless members here, I’m now converting a codebase to be mostly suspending. For the most part, this has been rather straightforward.
However, I have come across two issues where I haven’t been able to easily convert the code to be suspending.
The first issue is where the equals method needs to call a suspending function. I can’t move the functionality to a different function as instances of this specific class is used as a key in a HashMap. I obviously don’t want to add a runBlocking in the equals method, and I can’t see an easy solution to this.
The other issue is where the Comparator class where the comparison function is not suspending. This means that if the comparison function needs to call a suspending function, there is no way to use the built-in sorting function.
What’s the use case for equals to be suspending?
Usually classes for which equality makes sense are classes which just “store data” in memory and nothing else. (like references to external resources or such where suspending functions are very useful in dealing with).
A very short summary is that the project is a programming language interpreter where most values are lazily evaluated. Resolving the actual content of a value can be done in parallel (which is why everything is suspending). These values can be used as keys in a HashMap.
The use case for the sorting is similar. The language provides a function to sort elements, but since the elements are lazily evaluated, they need to call into the underlying evaluation function which is suspending.
If you need to run some lazy code to compute equals then I imagine you need to run that just to do anything.
So you could run that just after construction and make equals not lazy.
It’s not that simple. I wouldn’t mind explaining, but I’ll only do it if you’re really interesting in the answer, since I’d need to explain a lot of details.
I ended up solving the sorting problem by implementing a simple quicksort, which solves the problem for now. However, quicksort is less efficient than the built-in sort function so it would be nice to be able to use it.
The problem is that lazy values does not have a different type compared to computed values (“collapsed” in the terminology of my application). If a value is not lazy, its collapse method simply returns itself.
Now, even if this was possible, it would still not be ideal, since for sorting (i.e. the implementation of Comparable) all the values usually don’t need to be computed. For example, take two arrays, each a million elements long, but that differ in their first element. To order these, only the first element needs to be evaluated. In other words, it’s impossible to know how much to calculate before you actually perform a comparison.
For cases where you are checking equality like HashMap keys, waiting for the values to collapse still feels like the right approach in my mind.
I don’t have any suggestions better than a custom algorithm for the sorting case, but consider testing the performance of waiting for the values to collapse completely before you discount that approach for sorting. If the values aren’t used until they collapse, then maybe they don’t need to be sorted until they collapse.
Keep in mind, the sorting algorithm may not have such an impact compared to waiting for the values to collapse, even only partially, enough to do the comparison.