Derived Ordering for simple enum?

Hi all :raised_hand_with_fingers_splayed:

When I read the beginning of Type Class Derivation | Scala 3 Language Reference | Scala Documentation, I think to myself that I might be able to do the Scala equivalent of Haskell’s

data RGB = Red | Green | Blue 
  deriving(Eq,Ord,Show)

for Ordering, i.e.

enum RGB derives Ordering:
  case Red, Green, Blue

But that results in “value derived is not a member of object scala.math.Ordering”, so I end up doing this:

enum RGB:
  case Red, Green, Blue

given Ordering[RGB] with
  def compare(x: RGB, y: RGB): Int = x.ordinal compare y.ordinal

import RGB._

assert( List(Green, Red, Blue).sorted == List(Red, Green, Blue) )

Am I missing some trick? :slightly_smiling_face:

Thanks,

Philip

I think the problem here might be that Ordering wants your cases to be like Red(T), Green(T), Blue(T), where T already has an Ordering instance.

1 Like

The reason this isn’t working is that there needs to be some def derived[A]: Ordering[A] = ??? method in the Ordering companion object. Only the name really matters.

1 Like

:raised_hand_with_fingers_splayed: @Katrix

Thanks for taking the time to help.

Unless you are busy with something else, could you elaborate a bit? I mean, does your observation suggest a remedy for the code in question, a way to remove

given Ordering[RGB] with
  def compare(x: RGB, y: RGB): Int = x.ordinal compare y.ordinal

and do something simpler or better instead?

Do you have time to show me the code I could add instead?

If I misunderstand and you are too busy, then thank you anyway for your help.

Philip

It’s not an issue in your code, the standard library needs to be updated to define a derived method on Ordering, but Scala 3 uses the Scala 2.13 standard library which makes this tricky without compiler hacks.

6 Likes

@smarter thank you very much for that :+1:

Apparently extension methods on object Ordering are picked up as well. So one could write

extension (obj: Ordering.type)
  def derived[A]: Ordering[A] = ???
4 Likes

Thanks!

In case anyone is interested in a complete solution for enums, here it is:

/** allow derives Ordering for enums */
extension (obj: Ordering.type) {
  def derived[A <: reflect.Enum]: Ordering[A] = Ordering.by(_.ordinal)
}
4 Likes

Impressive necromancy skills! :joy:

Now when to expect this to arrive in the std. lib where it belongs?

1 Like

The current status is that we might finally be technically able to add to the Scala 2.13 standard library, or will be very soon. The next step is to decide what we actually need to add and to find qualified people to do it. I opened an issue to track this.

3 Likes

Given this is Scala 3 specific, does it belong to 2.13 library? It seems there is already a library distributed with Scala 3 - at least in my project I see scala3-library_3-3.5.1.jar containing e.g. boundary / break or CanEqual.

We can add new classes in the Scala 3 library, but we can’t add to existing classes in the Scala 2.13 library.

This is an extension. Can you please explain why it cannot be added to Scala 3 library? It does not modify any existing class, just extends it by providing what is technically a standalone function, is it not?

Where does the extension live?

It cannot live in the Ordering companion, which would be most natural, but it could live in some new object in scala.util, e.g. scala.util.extensions. That would require an import, like scala.collection.compat.- did, but nothing more.

Yes, but I don’t think we want an import. Maybe we can define it as a top-level definition in a file in the Scala package. I have not tried it. Not sure whether it would be workable or desirable. I foresee a lot of challenges with respect to discoverability.

1 Like

Then we should probably find some other way how to extend the library with things like this (Scala 3 only improvements). I do not like having all Scala 2 classes basically locked for the foreseeable future.

From my point of view this is more important than new language features.Unfortunately I do not see much progress made here since Scala 3 specific stdlib improvements - or even any significant interest in the subject.

1 Like

My solution to this problem usually is to simply extend java.lang.Enum. Java enums implement Comparable, so the Scala compiler can find an Ordering instance for them.

1 Like