lengthCompare, Why It's Needed, and Why It Needed to be Fixed

April Hyacinth
3 min readApr 23, 2019

What is lengthCompare?

It is recommended by experts and some IDEs to replace comparisons to Seq#length with calls to Seq#lengthCompare. What is lengthCompare? From the scaladoc:

For those familiar, this is the same contract used by Java’s Comparators and Scala's Orderings when comparing two values. If the first value is larger, a positive number is returned; if the second value is larger, a negative number is returned, and if they are equivalent, 0 is returned. Thus, seq.lengthCompare(x) is equivalent to Integer.compare(seq.length, x).

lengthCompare is Always Efficient

Why do I need lengthCompare though? I can just use the normal comparison operators, and it's much simpler. seq.length < 10 is much more readable than seq.lengthCompare(10) < 0.

Unfortunately, Seq#length can potentially be expensive. If you write seq.length < 10, you want to know if the Seq has fewer than ten elements. However, if the Seq has two million elements, it may have to traverse all two million to compute seq.length; this is highly inefficient if you only want to compare the length to a small number. Worse still, some Seqimplementations (e.g. LazyList or its predecessor Stream) may have infinitely many elements, in which case seq.length will never finish evaluating.

To solve this problem, lengthCompare iterates through at most one more element than the length compared against, unless it knows that length can be computed cheaply (see the scaladoc for the full details).

lengthCompare Usage is Awkward

The problem with lengthCompare is, it's ugly, somewhat difficult to read, and understanding code which uses it can require an extra layer of mental gymnastics (especially for beginners). It can take some time for your brain to automatically transform seq.lengthCompare(x) op 0 into seq.length op x (where op is <, >, etc.), and until then, code which uses lengthCompare can be quite confusing.

The Solution: lengthIs

To regain readability, we can use a new method: lengthIs. How do you use it? Exactly as if it was the length method.

Under the hood, lengthIs calls lengthCompare, so it's still very efficient, but it does some work to make the comparisons look natural and intuitive.

If all you wanted was a nicer way to compare Seq lengths, you can stop here; otherwise, see the Appendix to find out how lengthIs works.

Conclusion

lengthIs is a great new way to have readable code while retaining efficient computation. If you need to perform multiple comparisons on the result of lengthCompare, you can still use it, but in most cases, lengthIs will be preferable.

Additional Methods: sizeCompare and sizeIs

Scala 2.13 also adds sizeCompare and sizeIs methods, which do the same thing as lengthCompare and lengthIs, except they work on Iterable rather than just Seq.

Appendix: How Do lengthIs and sizeIs Work?

Unlike length and size which return Ints, lengthIs and sizeIs actually return a value class called IterableOps.SizeCompareOps, which defines six methods - the comparison operators (<, <=, ==, !=, >= and >). Each of these methods calls sizeCompare on the collection, and compares the result to 0 as appropriate.

Additionally, lengthIs, sizeIs and IterableOps.SizeCompareOps are defined carefully to have negligible overhead cost, so even in performance critical code, you can use lengthIs or sizeIs and have readable code without worrying about reducing efficiency (you can find the benchmark results here).

References

--

--