Skip to content

Cats Order needs an orElseBy combinator #4621

Open
@benhutchison

Description

Leaving aside the question of whether cats.Order existing (on top of scala.math.Ordering on top of java.util.Comparator) was wise decision 🙄 , at least it ought to be greaterThanOrEqual to its predecessor.

But alas, it lacks something valuable that Ordering has; a convenient syntax to construct a n-level hierarchical ordering for a record, by delegating to the orderings of several record fields. For example, if we have a case class Person(name: String, age: Int) we might wish to order by age but if ages are equal, use name as a discriminator. This is super common IME. Eg SQL has built in syntax for it order by age, name.

There are at least two attempts at addressing this in cats.Order, but alas both are less convenient than the (pre-existing) combinator in scala.math.Ordering:

def orElseBy[S](f: T => S)(implicit ord: Ordering[S]): Ordering[T]

Hence we find code like this in the wild:

      given Order[Single] = Order.fromOrdering(
      Ordering
        .by[Single, VPNTier](_.tier)
        .orElseBy(it => (it.lang1, it.lang2))
        .orElseBy(_.num)
        .orElseBy(_.postfix)
    )

The attempts in cats.Order are:

  • code. Order.whenEqual[Person](Order.by(_.age), Order.by(_.name)). Well it's already looking slightly awkward, but what if we wanted to add a 3rd discriminator? We'd need to nest it inside the second arg with another call to Order.whenEqual. Confusing right nesting.
  • code. The whenEqual Monoid is beautiful and tantalizes us with the promise of val o: Order[Person] = Order.by(_.age) |+| Order.by(_.name). But I could not get the types to infer properly even on Scala 3.5 RC1.

If it ain't broke, don't fix it. orElseBy does the job well and should be brought into Cats.

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions