Missing dedicated class for enum companions

The enum classes extend a common trait scala.reflect.Enum but the enum companions do not, which makes it difficult to generalize over without macros.

I think it will be better if enum companions extend scala.reflect.EnumCompanion, that is defined as:

trait EnumCompanion[E <: scala.reflect.Enum]:
  def values : Array[E]
  def valueOf(name : String) : E
19 Likes

It’s surprising that’s not the case. Seems very reasonable to me.

6 Likes

Looks reasonable. Maybe someone wants to do a PR?

5 Likes

I’ll try to take this on.

8 Likes

Great idea, would be very useful.

Is the reason values returns an Array instead of IArray for Java compat? A lot of developers complain that Java allocates a new Array on every call to values.

1 Like

Currently, we’ve been taking the approach to not generate values and valueOf for ADT enums - so perhaps there could be two subtypes of this class - one with the methods and one without.

I also think it would be good to expose the companion to implicit search - similar to how we summon Mirror in the compiler

7 Likes

Seconded, ScalaPb does this, and it’s extremely useful

3 Likes

What is the status of this? I really struggle with the usage of enums because of this.
Pattern matching is not working properly with the workaround suggested here: https://stackoverflow.com/a/69746693/2750966

It compiles (with warnings) but when packaging there are exceptions:
Caused by: java.lang.AssertionError: assertion failed: owner discrepancy for method values, expected: class <refinement>, found: method $anonfun

2 Likes

I started working on this.
What should we do if the user already defined a companion object for the enum?
A. Leave it as-is. That companion object will not be extending reflect.EnumCompanion.
B. Force extends of reflect.EnumCompanion.
C. Leave it as-is, but give a warning? (IMO, the worst choice).

After some experimentation, I realize that only singleton enums should have values and valueOf.
So we need to choose from:
A. Removing the methods from the body and just leave trait EnumCompanion[E <: scala.reflect.Enum]
B. Adding more refined traits such as SingletonEnumCompanion[E <: scala.reflect.Enum].
C. Drop this whole idea.

Created a PR. The only thing in question is what to do about companions which are defined by the user.

3 Likes

Somewhat related: the enum companion should be a case object (giving us a default hashCode implementation, improved toString, serialization, etc). The scala book documentation even hints at this:

Because of these features, case objects are primarily used in two places (instead of regular objects):

  • When creating enumerations
  • When creating containers for “messages” that you want to pass between other objects (such as with the Akka actors library)
1 Like