Problem with specifying enumeration value types - scala

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.

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)
}
}

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())
}
}

Related

Covariant data structure with numeric types

How do I create a covariant data structure containing numeric data types?
In scala I can create a covariant data structure, with a hierarchy of type parameters:
abstract class Car[+T] {
def value: T
}
class RaceCar extends Car[RacingWheel] {
def value: RacingWheel = new RacingWheel
}
class NormalCar extends Car[BoringWheel] {
def value: BoringWheel = new BoringWheel
}
class Wheel
case class RacingWheel() extends Wheel
case class BoringWheel() extends Wheel
object Car {
def main(args: Array[String]): Unit = {
val rCar: Car[Wheel] = new RaceCar
val nCar: Car[Wheel] = new NormalCar
val listCars: List[Car[Wheel]] = List(rCar, nCar)
}
}
However, when I replace the Wheel's with numeric data types I run into a problem, because the numeric data types do not have a common type parent other than AnyVal:
abstract class Item[+N] {
def value: N
}
class IntItem(x : Int) extends Item[Int] {
override def value: Int = x
}
class DoubleItem(x : Double) extends Item[Double] {
override def value: Double = x
}
object Item {
def main(args: Array[String]): Unit = {
// ERROR Expression of IntItem does not conform to expected type Item[Number]
val iItem: Item[Number] = new IntItem(10)
// ERROR Expression of DoubleItem does not conform to expected type Item[Number]
val dItem: Item[Number] = new DoubleItem(10.9)
val l: List[Item[Number]] = List(iItem, dItem)
// ERROR: Expression of IntItem does not conform to expected type Item[Double]
val iItem2: Item[Double] = new IntItem(10)
val dItem2: Item[Double] = new DoubleItem(10.9)
val l2: List[Item[Double]] = List(iItem2, dItem2)
}
}
Outside of the covariant data structure I get mixed results:
object NumberMain {
val a : Int = 5
val b : Double = 10.0
val list : List[Number] = List(a, b)
// works, so Number must be related to Int and Double, right?
val x : Number = 5
// ERROR: Expression of type Number doesn't conform to expected type Int
val y : Int = x
// does not work, so Number is not related to Int and Double after all...
}
What changes do I have to make to the Item data structure? Can I tell it that all items can be seen as of type numeric?
In Scala, Int and Double do not share hierarchy with a common Number class. The Typeclass pattern can help you in these cases to define extra features for types without a common supertype.
trait MyNumber[A]
implicit case object IntMyNumber extends MyNumber[Int]
implicit case object DoubleMyNumber extends MyNumber[Double]
class Item[N](x: N)(implicit n: MyNumber[N]) {
def value: N = x
}
The Item class constructor now expects a second group of parameters labeled with the implicit keyword. If you call the method without this group of parameters, the compiler tries to find it (an instance of MyNumber) from variables or imports also labeled with implicit (Where does Scala look for implicits?).
We're just defining here that Int and Double implements MyNumber, but it doesn't do anything. We can write then the class as:
class Item[N : MyNumber](x: N) {
def value: N = x
}
And it works as we expected:
val iItem = new Item(1)
val dItem = new Item(1.0)
scala> iItem.value
res1: Int = 1
scala> dItem.value
res2: Double = 1.0
If we try to build an item of anything without an instance of MyNumber, the compiler throws an error:
val sItem = new Item("S")
error: could not find implicit value for evidence parameter of type MyNumber[String]
If you want MyNumber to be any numeric, Scala implements a Numeric typeclass.
Edit
If you want to add some features to the typeclass that are different for each number, you can do:
trait MyNumber[A] {
def doStuff(a: A): Unit
}
implicit case object IntMyNumber extends MyNumber[Int] {
def doStuff(number: Int): Unit = println("Int")
}
implicit case object DoubleMyNumber extends MyNumber[Double] {
def doStuff(number: Double): Unit = println("Double")
}
case class Item[+N](x: N)(implicit myNumber: MyNumber[N]) {
def value: N = x
def doStuff = myNumber.doStuff(x)
}

Automatic type class derivation for case classes with Scala Enumeration fields

I have written automatic type class derivation in order to automatically generate elasticsearch Json mapping for case classes.
For that I am using the TypeClass type class in shapeless.
The problem I have is that many fields in the case classes we use are Scala enumerations.
For example
object ConnectionState extends Enumeration {
type ConnectionState = Value
val ordering, requested, pending, available, down, deleting, deleted, rejected = Value
}
Or
object ProductCodeType extends Enumeration {
type ProductCodeType = Value
val devpay, marketplace = Value
}
It seems I have to define a specific implicit instance for every Enumeration that is defined in order that the automatic derivation will pick it up (e.g. for both ConnectionState and ProductCodeType).
I cannot have one implicit def for Enumeration such as
implicit def enumerationMapping: MappingEncoder[Enumeration] = new MappingEncoder[Enumeration] {
def toMapping = jSingleObject("type", jString("text"))
}
that will work for all enumeration types.
I tried making the type class covariant, and a bunch of other things but nothing helped.
Any ideas?
Here is the derivation code:
object Mapping {
trait MappingEncoder[T] {
def toMapping: Json
}
object MappingEncoder extends LabelledProductTypeClassCompanion[MappingEncoder] {
implicit val stringMapping: MappingEncoder[String] = new MappingEncoder[String] {
def toMapping = jSingleObject("type", jString("text"))
}
implicit val intMapping: MappingEncoder[Int] = new MappingEncoder[Int] {
def toMapping = jSingleObject("type", jString("integer"))
}
implicit def seqMapping[T: MappingEncoder]: MappingEncoder[Seq[T]] = new MappingEncoder[Seq[T]] {
def toMapping = implicitly[MappingEncoder[T]].toMapping
}
implicit def optionMapping[T: MappingEncoder]: MappingEncoder[Option[T]] = new MappingEncoder[Option[T]] {
def toMapping = implicitly[MappingEncoder[T]].toMapping
}
object typeClass extends LabelledProductTypeClass[MappingEncoder] {
def emptyProduct = new MappingEncoder[HNil] {
def toMapping = jEmptyObject
}
def product[F, T <: HList](name: String, sh: MappingEncoder[F], st: MappingEncoder[T]) = new MappingEncoder[F :: T] {
def toMapping = {
val head = sh.toMapping
val tail = st.toMapping
(name := head) ->: tail
}
}
def project[F, G](instance: => MappingEncoder[G], to: F => G, from: G => F) = new MappingEncoder[F] {
def toMapping = jSingleObject("properties", instance.toMapping)
}
}
}
}
I was able to fix the problem by adding additional implicit defs to scope:
implicit def enumerationMapping[T <: Enumeration#Value]: MappingEncoder[T] = new MappingEncoder[T] {
def toMapping = jSingleObject("type", jString("text"))
}
implicit def enumerationSeqMapping[T <: Enumeration#Value]: MappingEncoder[Seq[T]] = new MappingEncoder[Seq[T]] {
def toMapping = jSingleObject("type", jString("text"))
}
The second implicit was needed as some of the case classes had members of type Seq[T] where T is some enumeration type.

Accessing class-level values of type parameters in Scala

I have a trait and a case class implementing it. One of the features of the trait that the implementations override is a default value. I can't find a good way to access this default value from a class that is parametrized by a specific implementation of that trait.
This is minimal code, so it doesn't really demonstrate the motivation anymore, but it does demonstrate the error:
import scala.language.implicitConversions
trait Distance[T] {
val Zero: T
def +( that: T ): T
}
case class DoubleDistance( val v: Double ) extends Distance[DoubleDistance] {
val Zero = DoubleDistance( 0.0 )
def +( that: DoubleDistance ) = DoubleDistance( v + that.v )
}
object DistanceImplicits {
implicit def DoubleToDistance( v: Double ) = new DoubleDistance( v )
}
class User[T<:Distance[T]] {
val default: T = T.Zero // This line gives me a compilation error
}
The error I get is
not found: value T
When I needed to construct an Array[T] inside my User class I could get that to work by adding implicit typetag:ClassTag[T] to my arguments, but that doesn't seem to have any effect here.
First, why this doesn't work: consider a different implementation of Distance.
case class DoubleDistance1(val v: Double) extends Distance[DoubleDistance1] {
val Zero = this
def +(that: DoubleDistance1) = ??? // doesn't matter
}
What would you expect DoubleDistance1.Zero to mean? You can make it work using a "type class":
trait DistanceOps[T] {
val zero: T
def add(d1: T, d2: T): T
}
// just to let you write distance1 + distance2
implicit class RichDistance[T](d: T)(implicit ops: DistanceOps[T]) {
def +(other: T) = ops.add(d, other)
}
case class DoubleDistance(v: Double)
object DoubleDistance {
implicit object DoubleDistanceOps extends DistanceOps[DoubleDistance] {
val zero = DoubleDistance(0.0)
def add(d1: DoubleDistance, d2: DoubleDistance) = DoubleDistance(d1.v + d2.v)
}
}
// how to use
class User[T](implicit ops: DistanceOps[T]) {
val default: T = ops.zero
}
This looks like a classic use case for the type class pattern. Rather than associating an instance of the Distance trait with each value of interest, you associate one with each type of interest:
trait Distance[T] {
val Zero: T
def +( a: T, b: T ): T
}
implicit object DoubleDistance extends Distance[Double] {
val Zero = 0.0
def +( a: Double, b: Double ) = a + b
}
class User[T : Distance] {
val default: T = implicitly[Distance[T]].Zero
}
Where is that Zero supposed to come from? Are you looking to do something like this?
class User[T<:Distance[T]] {
self:Distance[T] =>
val default: T = Zero
}

How to avoid awful type casts working with path dependent types?

I am new to Scala and dont know why i have to do an (unintuitive for me) type cast related to path dependent types in the following code.
(I don't like getters, setters nor nulls, they are here to separate operations and disambiguate the source of errors)
// Module A public API
class ModA {
trait A
}
// Module B public API that depends on types defined in Module A
class ModB(val modA: ModA) {
trait B {
def getA: modA.A;
def setA(anA: modA.A);
}
}
// One implementation of Module A
class ModAImpl extends ModA {
class AImpl extends A
}
// One implementation of Module B
class ModBImpl(mod: ModA) extends ModB(mod) {
class BImpl extends B {
private[this] var privA: modA.A = _;
override def getA = privA;
override def setA(anA: modA.A) = privA = anA;
}
}
object Main {
def main(args: Array[String]): Unit = {
// wiring the modules
val modAImpl = new ModAImpl;
val modBImpl = new ModBImpl(modAImpl);
// wiring objects
val a = new modAImpl.AImpl;
val b = new modBImpl.BImpl;
b.setA(a); //don't compile and complain: type mismatch; found: modAImpl.A required: modBImpl.modA.A
//i have to do this horrible and coutnerintuitive cast to workaround it
b.setA(a.asInstanceOf[modBImpl.modA.A]);
var someA: modAImpl.A = null;
someA = b.getA; // don't compile with same reason
someA = b.getA.asInstanceOf[modAImpl.A]; // horrible cast to workaround
println(a == b.getA); // however this prints true
println(a eq b.getA); // this prints true too
}
}
I have read about singleton types to inform the compiler when two types are the same, but I don't know how to apply this here.
Thanks in advance.
You can stick a type parameter on the ModB types:
class ModA { trait A }
class ModB[AA](val modA: ModA { type A = AA }) {
trait B {
def getA: AA
def setA(anA: AA)
}
}
class ModAImpl extends ModA { class AImpl extends A }
class ModBImpl[AA](
mod: ModA { type A = AA }) extends ModB(mod) {
class BImpl extends B {
private[this] var privA: AA = _
override def getA = privA
override def setA(anA: AA) = privA = anA
}
}
And the type inference all works out as desired:
scala> val modAImpl = new ModAImpl
modAImpl: ModAImpl = ModAImpl#7139edf6
scala> val modBImpl = new ModBImpl(modAImpl)
modBImpl: ModBImpl[modAImpl.A] = ModBImpl#1dd7b098
scala> val a = new modAImpl.AImpl
a: modAImpl.AImpl = ModAImpl$AImpl#4cbde97a
scala> val b = new modBImpl.BImpl
b: modBImpl.BImpl = ModBImpl$BImpl#63dfafd6
scala> b.setA(a)
Let's start by simplifying your code ridding out the unnecessary complexity.
class Aout {
class Ain
}
class Bout(val link: Aout) {
class Bin(val field: link.Ain)
}
object Main {
def main(args: Array[String]): Unit = {
// wiring outer object
val aout: Aout = new Aout;
val bout: Bout = new Bout(aout);
// wiring inner object
val ain: aout.Ain = new aout.Ain;
val bin: bout.Bin = new bout.Bin(ain); //don't compile and complain: type mismatch; found: aout.Ain required: bout.link.Ain
}
}
Answer:
The compiler complains with a type mismatch error because he compares the paths of the two declared types involved in the assignment, and they are different.
The compiler is not intelligent enough to notice that at that point aout eq bout.link. You have to tell him.
So, replacing the line
val ain: aout.Ain = new aout.Ain;
with
val ain: bout.link.Ain = new bout.link.Ain;
solves the path-dependent type mismatch.
Anyway, correcting the type's path in your original code is not enough because there is also an inheritance problem.
One solution to that is to make the class ModBImpl know the ModAImpl class like this:
class ModA {
trait A
}
class ModB[M <: ModA](val modA: M) { // type parameter added
trait B {
def getA: modA.A;
def setA(anA: modA.A);
}
}
class ModAImpl extends ModA {
class AImpl extends A
}
class ModBImpl(mod: ModAImpl) extends ModB(mod) { // changed type of `mod` parameter from `ModA` to `ModAImpl`
class BImpl extends B {
private[this] var privA: modA.A = _;
override def getA: modA.A = privA;
override def setA(anA: modA.A): Unit = privA = anA;
}
}
object Main {
def main(args: Array[String]): Unit = {
val modAImpl = new ModAImpl;
val modBImpl = new ModBImpl(modAImpl);
val a: modBImpl.modA.AImpl = new modBImpl.modA.AImpl; // changed the path of the type
val b: modBImpl.BImpl = new modBImpl.BImpl;
b.setA(a); // here IntellijIde complains with a type mismatch error, but the ScalaIDE (eclipse) and the scala compiler work fine.
}
}
If the rules of your business don't allow that the ModBImpl class has knowledge of the ModAImpl class, tell me so we can find another solution.

scala: add methods to an enum

I have a simple enum like this:
object ConditionOperator extends Enumeration {
val Equal = Value("equal")
val NotEqual = Value("notEqual")
val GreaterOrEqual = Value("greaterOrEqual")
val Greater = Value("greater")
val LessOrEqual = Value("lessOrEqual")
val Less = Value("less")
And I'd like to add a method to each enum so that I can use it like this:
def buildSqlCondition(field: String, operator: ConditionOperator.Value, value: String ) = {
val sqlOperator = operator.toSql
[...]
So, ConditionOperator.Equal.toSql wuld return "=", and ConditionOperator.NotEqual.toSql would return "<>", etc...
But I don't know how to define a toSql method, so that each enum can "see" it's own value and decide how to translate itself to a sql operator...
This is an example of what I have found for Scala 2.9.2 from various searches on the topic in the past:
object Progress extends Enumeration {
type enum = Value
val READY = new ProgressVal {
val isActive = false
def myMethod: Any = { .. }
}
val EXECUTE = new ProgressVal {
val isActive = true
def myMethod: Any = { .. }
}
val COMPLETE = new ProgressVal {
val isActive = false
def myMethod: Any = { .. }
}
protected abstract class ProgressVal extends Val() {
val isActive: Boolean
def myMethod: Any
}
implicit def valueToProgress(valu: Value) = valu.asInstanceOf[ProgressVal]
}
type Progress = Progress.enum
The implicit is key to making this usable.
The type enum and type Progress are somewhat redundant; I include them to present both concepts as something I've found helpful.
To give credit where it's due, the original idea for this came from Sean Ross in a response to a question of which this one is a duplicate.
You can start by defining an inner class that overrides Enumeration.Val. To simplify things, let's call it Value (we overload the original meaning of Value as defined in Enumeration).
So we have our new Value type which inherits Enumeration.Val which itself inherits Enumeration.Value.
Given that toSql has no side effects and returns a different string for each enumeration, you might as well just make it a val.
Finally, to make it fully usable, you'll want to have ConditionOperator.apply and ConditionOperator.withName to return your newly defined Value class instead of the Value type as defined in Enumeration.
Otherwise, when using apply or withName to look up an instance of ConditionOperator by index/name, you won't be able to call toSql because the enumeration type will not be specific enoough.
Ideally we'd like to just override apply and withName and add a cast to ConditionOperator.Value, but these methods are final.
However we can employ a small trick here: define new methods apply and withName with the same signature but an additional implicit parameter that will always be available (Predef.DummyImplicit fits this rolle perfectly).
The additional parameter ensures that the signature is different so that we are able to define these new methods, while at the same time being nearly indistinguishable from the original apply/withName methods.
The rules for overloading resolution in scala ensure that our new methods are the ones favored by the compiler (so we have in practice shadowed the original methods).
object ConditionOperator extends Enumeration {
// Here we overload the meaning of "Value" to suit our needs
class Value(name: String, val toSql: String) extends super.Val(name) {
def someFlag: Boolean = true // An example of another method, that you can override below
}
val Equal = new Value("equal", "=")
val NotEqual = new Value("notEqual", "<>")
val GreaterOrEqual = new Value("greaterOrEqual", ">=")
val Greater = new Value("greater", ">")
val LessOrEqual = new Value("lessOrEqual", "<=") { override def someFlag = false }
val Less = new Value("less", "<")
final def apply(x: Int)( implicit dummy: DummyImplicit ): Value = super.apply(x).asInstanceOf[Value]
final def withName(s: String)( implicit dummy: DummyImplicit ): Value = super.withName(s).asInstanceOf[Value]
}
You can check that you can now do things like ConditionOperator(2).toSql or ConditionOperator.withName("greaterOrEqual"), which both return ">=" as expected.
Finally, the above gymnastic can be abstracted away:
abstract class CustomEnumeration extends Enumeration {
type BaseValue = super.Val
type CustomValue <: super.Value
type Value = CustomValue
final def apply(x: Int)( implicit dummy: DummyImplicit ): CustomValue = super.apply(x).asInstanceOf[CustomValue]
final def withName(s: String)( implicit dummy: DummyImplicit ): CustomValue = super.withName(s).asInstanceOf[CustomValue]
}
object ConditionOperator extends CustomEnumeration {
class CustomValue(name: String, val toSql: String) extends BaseValue(name) {
def someFlag: Boolean = true
}
val Equal = new Value("equal", "=")
val NotEqual = new Value("notEqual", "<>")
val GreaterOrEqual = new Value("greaterOrEqual", ">=")
val Greater = new Value("greater", ">")
val LessOrEqual = new Value("lessOrEqual", "<=") { override def someFlag = false }
val Less = new Value("less", "<")
}
object ConditionOperator extends Enumeration {
implicit def overrideValue(v:Value) = new OverridedValue(v)
class OverridedValue(val v:Value) {
def toSql = v.toString
}
val Equal = Value("=")
val NotEqual = Value("<>")
val GreaterOrEqual = Value(">=")
val Greater = Value(">")
val LessOrEqual = Value("<=")
val Less = Value("<")
}
import ConditionOperator._
assert(Equal.toSql == "=")
And in scala 2.10, you can make it simpler by using implicit class, replace
implicit def overrideValue(v:Value) = new OverridedValue(v)
class OverridedValue(val v:Value) {
def toSql = v.toString
}
with
implicit class OverridedValue(val v:Value) {
def toSql = v.toString
}