Search code examples
scalascala-3

How do you define an enum that can only be created by its companion object? (think smart constructors)


I've tried making the constructor private, like this:

enum X {
  case Stuff private (value: Int)
}

object X {
  def stuff(s: String) = 
    X.Stuff(performSomeValidationAndCalculation(s))
}

but it complains:

method apply cannot be accessed as a member of Playground.X.Stuff.type from module class X$

I would like to force callers to use the smart constructor to prevent an invalid enum from being instantiated and to limit the number of introduction forms.


Solution

  • Just add the class name to private to limit the scope:

    enum X {
      case Stuff private[X] (value: Int)
    }
    
    object X {
      def stuff(s: String) = 
        X.Stuff(s.toInt)
    }
    

    Sample working code: https://scastie.scala-lang.org/hUPECAJFSzqAus6c5slBHQ