2

I have a problem with specifying types for enumeration values (instances of scala.Enumeration) in functions. This originally arises from my need to serialize enumeration objects in database, but I've extracted the problematic code in the following example:

object EnumerationTypes {

  class EnumerationProcessor[E <: Enumeration](enum: E, value: E#Value) {
    def process: E#Value = {
      value
    }
  }

  object Enum extends Enumeration {
    type EnumValue = Value

    val a = Value(1, "a")
    val b = Value(2, "b")
  }

  case class Obj(val flag: Enum.EnumValue)

  def main(args: Array[String]) {
    val processor = new EnumerationProcessor(Enum, Enum.a)
    val obj = Obj(processor.process)
  }
}

It leads to the following compilation error:

error: type mismatch;
 found   : EnumerationTypes.Enum#Value
 required: EnumerationTypes.Enum.EnumValue
    val obj = Obj(processor.process)

While this works ok:

object EnumerationTypesOk {

  class EnumerationProcessor[E <: Enumeration](enum: E, value: E#Value) {
    def process: E#Value = {
      value
    }
  }

  class Enum extends Enumeration {
    type EnumValue = Value

    val a = Value(1, "a")
    val b = Value(2, "b")
  }
  object Enum extends Enum

  case class Obj(val flag: Enum#EnumValue)

  def main(args: Array[String]) {
    val processor = new EnumerationProcessor(Enum, Enum.a)
    val obj = Obj(processor.process)
  }
}

But I don't want my code to be looks like this (first define class and then its singleton instance).

So the problem: how I can make value type be exactly the enum.EnumValue? While it seems impossible, because types cannot depend on concrete values, maybe there are some tricks to achieve desired effect with no additional boilerplate.

2

2 Answers 2

1

Edit:

Looks like you just need to help the type inferencer a bit to get your first solution working:

val processor = new EnumerationProcessor[Enum.type](Enum, Enum.a)

Hopefully someone smarter than I am will come along and explain why.

Before the OP's clarifying comment:

object EnumerationTypes {

   class EnumerationProcessor[E <: Enumeration, V <: E#Value](enum: E, value: V) {
      def process: V = {
        value
      }
   } 

   object Enum extends Enumeration {
      type EnumValue = Value

      val a = Value(1, "a")
      val b = Value(2, "b")
   }

   case class Obj(val flag: Enum.EnumValue)

   def main(args: Array[String]) {
      val processor = new EnumerationProcessor(Enum, Enum.a)
      val obj = Obj(processor.process)
   }
}
Sign up to request clarification or add additional context in comments.

1 Comment

The problem with this solutions is V is not compatible with E.Value — and if I want to do inside processor something like enum.values.find { _ == value } it will not typecheck.
1

Another potential solution is to define a mixin that allows you to create a 'processor' for a particular Enumeration instance:

object EnumerationTypes {
   trait EnumerationProcessor { self: Enumeration =>
      def processor(value: self.Value): () => self.Value = () => { 
         value 
      }
   }

   object Enum extends Enumeration with EnumerationProcessor {
      type EnumValue = Value

      val a = Value(1, "a")
      val b = Value(2, "b")
   }

   case class Obj(val flag: Enum.EnumValue)

   def main(args: Array[String]) {
      val processor = Enum.processor(Enum.a)
      val obj = Obj(processor())
   }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.