Scala 3 enum method override

Viewed 458

Is there a way to override method in Scala 3 enum just like in Java?

public enum Test {

    ONE {
        @Override
        public int calc() {
            return 1;
        }
    },
    TWO {
        @Override
        public int calc() {
            return 2;
        }
    };

    public abstract int calc();
}

I've tried something like this, but no result. Also haven't found anything about enum methods overriding in documentation.

enum Test {
  def calc(): Int ={
    0
  }
  case One
    override def calc(): Int ={
      1
    }
  case Two
    override def calc(): Int ={
      2
    }
}

Maybe there is another way to achieve similar functionality?

3 Answers

The enum is sealed, so it cannot be extended after the fact, so there is no reason to override anything. Just collect all cases in one place, and instead of multiple override-methods, write one single method which covers all the cases:

enum A:
  case X(x: Int)
  case Y(y: String)
  def foo: String = this match {
    case X(x) => s"X = ${x}"
    case Y(y) => y
  }

val x = new A.X(42)
val y = new A.Y("y")
println(x.foo) // X = 42
println(y.foo) // y

It seems what you want is currently not possible, but there are other ways to do it. You could try an old-school sealed trait with objects that override calc.

sealed trait Test:
  def calc: Int
object One extends Test:
  def calc = 1
object Two extends Test:
  def calc = 2

The function calc could also be made a parameter of Test, although I like this method less.

enum Test(calc: () => Int):
  case One extends Test(() => 1)
  case Two extends Test(() => 2)

Another way to do it would be through a single method and pattern matching, as gianluca aguzzi and Andrey Tyukin did, although an extension method is unnecessary.

If calc has to be a function, I would suggest the first approach, or pattern matching if you feel it suits you better. Sealed traits are also a good option if you want to override multiple methods, since you don't need to pattern match separately or lump a bunch of lambdas into a constructor call. If it's not a function, I feel the second would work best.

In scala 3, you can achieve a similar result combining enum with extension method:

enum Test {
  case One, Two
}

extension (test: Test)
  def calc() : Int = test match {
    case Test.One => 1
    case Test.Two => 2
  }

I hope I helped you :)

Related