Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reference scala Enumeration from other package

I'm having trouble understanding why I can't reference a scala enum type.

The problem is that sometimes I can reference enums:

enum(UserStatus)

and sometimes it complains about not being able to find the enum

not found: type UserStatus

How come I sometimes cannot reference the Enumeration class?

The generated source for the enum seems to be ok, and it works great with another enum that I have which lives in the same place, same usage...

Any Suggestions?

More info

The generated source for the enum is:

public final class models.UserStatus extends java.lang.Object{
    public static final scala.Enumeration$Value Busy();
    public static final scala.Enumeration$Value Free();
    public static final scala.Enumeration$ValueSet$ ValueSet();
    public static final scala.Enumeration$Value withName(java.lang.String);
    public static final scala.Enumeration$Value apply(int);
    public static final int maxId();
    public static final scala.Enumeration$ValueSet values();
    public static final java.lang.String toString();
}

I'm trying to implement an enum mapper for play framework 2.0

def enumFormat[E <: Enumeration](enum: E): Formatter[E#Value] = new Formatter[E#Value] {
  def bind(key: String, data: Map[String, String]) = {
    Formats.stringFormat.bind(key, data).right.flatMap { s =>
      scala.util.control.Exception.allCatch[E#Value]
        .either(enum.withName(s))
        .left.map(e => Seq(FormError(key, "error.enum", Nil)))
    }
  }
  def unbind(key: String, value: E#Value) = Map(key -> value.toString)
}

And this method that calls the mapper

def enum[E <: Enumeration](enum: E): Mapping[E#Value] = of(enumFormat(enum))

This means that the mapper automatically converts between a enum when using the form binding

Pseudo code of usage.

package models {
  object UserStatus extends Enumeration {
    val Free = Value("free")
    val Busy = Value("busy")
  }

  case class User(
    status: UserStatus.Value = UserStatus.Free
  )
}

package controllers {
  imports models._
  val userForm = Form(
    mapping(
      "status" -> enum(UserStatus)
    )(User.apply)(User.unapply)
  )
}
like image 995
Leon Radley Avatar asked Dec 28 '22 02:12

Leon Radley


1 Answers

Your problem may come from the fact that in Scala you can use the same identifier for a type and for a value.

When you write the following:

object Foo extends Enumeration {
  val A, B, C = Value
}

You define a Foo object, but you don’t define a Foo type. If you come from a Java background you may not find this behavior intuitive.

So what’s the type of the Foo enumeration values? Their type is Foo.Value (that’s called a path dependent type).

If you want to define a Foo type corresponding to the enumeration values type, you can alias the Foo.Value type:

object Foo extends Enumeration {
  type Foo = Value    // Type alias
  val A, B, C = Value
}

Now you can refer to the enumeration type by writing Foo.Foo. You can import the fields of the Foo object to reduce the syntactic overhead:

import Foo._
def bar(foo: Foo): String = foo match {
  case A => "value A"
  case B => "value B"
  case C => "value C"
}

In the above code, the first line refers to the Foo object, and the second line refers to the Foo type.

like image 123
Julien Richard-Foy Avatar answered Jan 18 '23 23:01

Julien Richard-Foy