Find the N minimum elements

It does.

def takeNsmallest[T : Ordering](n: Int, data: List[T]): List[T]

Which is equivalent to

def takeNsmallest[T](n: Int, data: List[T])(implicit ord: Ordering[T]): List[T]

Because I wouldn’t know how to get Scastie to pull in the jmh dependency. The code is intended to be run with sbt-jmh.

I’m beginning to think maybe I do understand, and simply disagree. To me the knowledge of how to take the n Locations closest to a given center point DOES NOT belong in the definition of Location. Sorting relative to a center-point is an application specific task, not something which is part of what a Location is. In an application I might want to sort a List of Locations many many different ways. It depends on the application, not on the essence of what a Location is. This particular application is using a particular data structure (sortedIterator) to implement an approximately linear complexity algorithm, which needs to sort data in an application specific way.

There are two reasons in general you might want to sort a List. 1) simply because you need a deterministic order independent of the order the elements are generated. 2) because there may be some semantic meaning to a particular order. Case 1, should go in the object’s definition. Case 2, belongs in the application, and may be expressed many different ways in many different applications or many different ways in the same application.

For the moment I will simply admit defeat. It is a topic I’d rather discuss face to face with someone with beers in hand. I’ll be happy to treat anyone to a beer who wishes to discuss this further.

Thanks everyone for your kind attempts to help me understand a confusing topic.

You get the application-specific way exactly with

println(locs.sorted(Location.orderingByDist(Location(1, 0))))

And this just incidentally uses code that is defined in the Location companion object. You could just as well do

println(locs.sorted(Ordering.by[Location, Double](_.x)))
// List(Location(-1.0,-2.0), Location(0.0,2.0), Location(0.0,0.0), Location(1.0,2.0), Location(1.0,0.0))

or whatever ordering you like.

And no, you don’t have to define a default implicit ordering in the companion object. (This should only be done if there’s a natural ordering on this type, and that can be tricky - Scala 2.13 just deprecated the default ordering for Double, since it’s not as clear-cut as it seemed.) I just added this to cover two “levels” of implicit lookup, but sorting by distance to origin certainly doesn’t feel like an actual natural ordering for locations. You could just leave this out and require clients to always provide their own - either via an implicit in some limited scope, or as an explicit argument.

To sum up, the only difference to your “measure function” approach is that

a) through the implicits mechanism the compiler can optionally look up an argument value from scope if it’s not explicitly provided at the call site and that

b) Ordering better matches the semantics for sorting/finding mins and the provisions present in the Scala standard library ecosystem - there will be lots of types that come with a predefined ordering, but not so many with a conversion to Double.