Generic enum using case class in scala - scala

I have created the following enum objects
sealed trait MsgMapping[T] {def mycode: T;}
object Type1 {
sealed trait msg[Int] extends MsgMapping[Int]
case object A extends msg[Int]{val myCode = 0;}
case object B extends msg[Int]{val myCode = 1;}
}
object Type2 {
sealed trait msgtype[String] extends MsgMapping[String]
case object C extends msgtype[String]{val myCode = "xyz";}
case object D extends msgtype[String]{val myCode = "def";}
}
I want to create a generic case class that can except any type of MessageMapping ,it can be an Integer/String or any data type
But this line gives error as it expects the type.
case class EumType(valueType: MsgMapping [T])
The below works
case class EumType1(valueType: MsgMapping [Int])
case class EumType2(valueType: MsgMapping [String])
case class TestEnum(value:EumType1)
case class Test(val:TestEnum)
But I do not want to create EumType1 and EumType2 .Can anyone help to me to create a generic code for this
Update
As per suggestion
case class EnumType[T](valueType: MsgMapping[T])
case class TestEnum(value:EnumType[T])
It will throw compile error since it expects type
here but i want to pass the type on this line
case class Test(val:TestEnum) ,whether it is Type1 /Type2

Try using an existential type:
case class EumType(valueType: MessageMapping [_])

Related

Scala: Inherited enum object doesn't satisfy parent trait

I am trying to use an Enumeration object in a method. The enum object extends from a trait, and the method takes the trait as a parameter. Here is the sample code.
sealed trait canAdd
object DAdder extends Enumeration with canAdd
{
type DAdder = Value
val P, Q = Value
}
class ClassTypeTest extends AnyFlatSpec with Matchers
{
class AClass
{
def add(v: canAdd) = if(v.isInstanceOf[DAdder]) println("Got DAdder") else println("Got IAdder")
def note(v: canAdd) = println("Got some canAdd trait object")
}
val aobj = new AClass
val aseq: Seq[DAdder] = Seq(DAdder.P, DAdder.Q, DAdder.P)
//*** Error in below line *****
aseq.foreach(aobj.add(_))
}
The compiler gives the following error:
Error:(23, 23) type mismatch;
found : x.x.DAdder.DAdder
(which expands to) x.x.DAdder.Value
required: x.x.canAdd
aseq.map(aobj.add(_))
Shouldn't I be able to pass an object that inherits the trait in a method that takes the trait as an argument? How do I fix this?
Enumeration class doesn't allow you to extends its values functionality. It is basically:
abstract class Enumeratum {
sealed trait Value { /* utilities */ }
object Value { /* factory of Values */ }
// utilities
}
Since you have the control only on Enumeratum class you cannot extend Values which is what you ask for.
You can easily have this functionality with sealed traits and case objects
sealed trait DAdder extends canadd
object DAdder {
case object P extends DAdder
case object Q extends DAdder
}
This however misses some utilities like finding value by its name, listing all values, etc.
This problem is solved by Enumeratum library which require that you mix in some traits and cope paste one line (val values = findValues) to have all functionalities of Enumeration and more
import enumeratum._
sealed trait DAdder extends canadd
with EnumEntry // mixin here
object DAdder extends Enum[DAdder] { // and mixin here
case object P extends DAdder
case object Q extends DAdder
val values = findValues // and one line calling macro
}
(There are also specializations for enums that should store some primitives/strings as their values in enumeratum.values._).
In Scala 3 this will probably look slightly different as it introduced enum keyword
sealed trait DAdder extends canadd
object DAdder {
case object P extends DAdder
case object Q extends DAdder
}
will become
enum DAdder extends canadd {
case P, Q
}
Scala 3's enum will ordinal method defined, so libraries like Enumeratum will have to provide a little fewer functionalities. (I guess by mixing in Java's Enum trait you will have access to values so everything else is a matter of extension methods).

Combine related ADTs in a type safe way

I'm designing a typesafe api to work with a "types" -- an abstraction in the application I'm working on. Here is how it looks like:
sealed trait EnumType
case object A extends EnumType
case object B extends EnumType
case object C extends EnumType
sealed abstract class TypeInfo[T <: EnumType](val enumType: T)
case class Ainfo() extends TypeInfo(A)
case class Binfo() extends TypeInfo(B)
case class Cinfo() extends TypeInfo(C)
sealed trait TypeMeta[T <: EnumType]
case class Ameta() extends TypeMeta[A.type]
case class Bmeta() extends TypeMeta[B.type]
case class Cmeta() extends TypeMeta[C.type]
case class TypeDescription[T <: EnumType](info: TypeInfo[T], meta: TypeMeta[T])
I'm confused about defining a function which would accept a List of TypeInfo and return TypeDescription. I currently implemeted it as follows:
//Type parameter with omitted bound? Is that type safe?
def toDescription(lst: List[TypeInfo[_]]): List[TypeDescription[_]] = {
lst map {
case a: Ainfo => TypeDescription(a, Ameta())
case b: Binfo => TypeDescription(b, Bmeta())
case c: Cinfo => TypeDescription(c, Cmeta())
}
}
To workaround the issue I used [_] pattern which does not look typesafely. Is there a way to redeclare the function?
Its type safe , however the 2 type parameters are bound individually to their own constraints and not to one another.
If you are looking to do that , I think you would need to define a method type parameter like so
//Type parameter with omitted bound? Is that type safe?
def toDescription[T<:EnumType](lst: List[TypeInfo[T]]): List[TypeDescription[T]] = {
lst map {
case a: Ainfo => TypeDescription(a, Ameta())
case b: Binfo => TypeDescription(b, Bmeta())
case c: Cinfo => TypeDescription(c, Cmeta())
}
}
Now if you tried to write
case a: Ainfo => TypeDescription(a, Bmeta())
you will get a compilation error

Exhaustive match on possible object values

First the code:
object MyEnums {
sealed abstract class MyEnum(val value: String)
case object First extends MyEnum("Some_ugly_looking_value1")
case object Second extends MyEnum("Some_ugly_looking_value2")
case object Third extends MyEnum("Some_ugly_looking_value3")
case object Fourth extends MyEnum("Some_ugly_looking_value4")
def fromString(value: String): Option[MyEnum] =
value match {
case First.value => Option(First)
case Second.value => Option(Second)
case Third.value => Option(Third)
case Fourth.value => Option(Fourth)
case _ => None
}
}
What I'm trying to achieve here is to be able to parse a string value coming from the outside into the form of the above enum. At the same time I would like to have the exhaustive pattern matching compiler warning if I don't cover all options in the match expression. What options do I have here? I don't like what I implemented above, since if this enum grows I may just forget to implement the new case clause...
Consider enumeratum like so
import enumeratum._
sealed abstract class MyEnum(override val entryName: String) extends EnumEntry
object MyEnum extends Enum[MyEnum] {
val values = findValues
case object First extends MyEnum("Some_ugly_looking_value1")
case object Second extends MyEnum("Some_ugly_looking_value2")
case object Third extends MyEnum("Some_ugly_looking_value3")
case object Fourth extends MyEnum("Some_ugly_looking_value4")
}
MyEnum.withName("Some_ugly_looking_value1") // res1: MyEnum = First
Now we do not have to fiddle with pattern match when adding a new case object.

Scala Multiple Nested Case Clases

Good day everyone, I create the following case class on SCALA:
sealed abstract class Value;
case class U(name: String) extends Value
case class L(name: String) extends Value
case class B(name: String) extends Value
sealed abstract class Term
case class Var(name: String) extends Term //variable name
case class Val(value: Value) extends Term //value
sealed abstract class Pattern //patterns
case class BGP(subject: Term, predicate: Term, obj: Term) extends Pattern
case class And( pat1: Pattern, pat2: Pattern) extends Pattern
case class Filter(pred: Predicate, pattern: Pattern ) extends Pattern
def function(p: Pattern): Unit = p match {
case BGP(Var(x), Val(y), Val(z)) => {
val con:conv = new conv()
val valor:Value = Val(y).value
}
Then, as you can see, BGP contains Term and extends to pattern, Val contains Values and extends to Term, and U,L,B contains Strings and extends to Value,
In my function I want to access to the strings that contains the U or L or B case classes, the variable valor = Val(y).value contains a U class for example, but when I write valor.XXXX don't appear me the name option. The big question is How can I do to accesss to the String name from U?
You just define it on Value which btw could be a trait.
sealed trait Value {
def name: String
}
case class U(name: String) extends Value
case class L(name: String) extends Value
case class B(name: String) extends Value

Does Scala have an equivalent of F#'s "type of"?

An example of type declaration in F#:
type ActiveCartData = { UnpaidItems: string list }
type PaidCartData = { PaidItems: string list; Payment: float }
type ShoppingCart =
| EmptyCart // no data
| ActiveCart of ActiveCartData
| PaidCart of PaidCartData
How could we do something similar in Scala using trait and case class and/or case object?
A start:
trait ShoppingCart
case object EmptyCart extends ShoppingCart
case object ActiveCart extends ShoppingCart
case object PaidCart extends ShoppingCart
But how to make the relationship with the data holder types?
If I understand correctly, you are looking for case classes instead of case objects. They can wrap data:
sealed trait ShoppingCart
case object EmptyCart extends ShoppingCart
case class ActiveCart(unpaidItems: Seq[String]) extends ShoppingCart
case class PaidCart(paidItems: Seq[String], payment: Float) extends ShoppingCart
or (if you want to keep these holder data types, which I would probably not do unless they are very complex)
sealed trait ShoppingCart
case object EmptyCart extends ShoppingCart
case class ActiveCart(unpaidItems: ActiveCartData) extends ShoppingCart
case class PaidCart(paidItems: PaidCartData) extends ShoppingCart