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.
Related
I have the following Type that i need to model:
sealed trait FieldType
case object INT extends FieldType
case object UINT extends FieldType
case object FLOAT extends FieldType
case object DOUBLE extends FieldType
case object BOOL extends FieldType
case object STRING extends FieldType
case object DATETIME extends FieldType
case class LIST(fieldType: FieldType) extends FieldType
case class SET(fieldType: FieldType) extends FieldType
The Issue i have is that in fact LIST and SET are actually ComplexFieldType that contain FieldType. In other words LIST Can Not Contain List or SET, same thing for SET.
What would be the proper way to model that, to ensure exhaustivity issue i.e. having the compiler telling me when i am missing some values.
I tried to introduce intermediary sealed trait as in SimpleFieldType and ComplexFieldType but then the pattern matching was messed up.
Only solution that i see if I don't want to compound things as in
case object LIST_INT
is to use smart constructor for LIST and SET.
However I thought drop a note and see what the scalaSphere knows about it.
It works indeed as such:
sealed trait FieldType
sealed trait SimpleFieldType extends FieldType
case object INT extends SimpleFieldType
case object UINT extends SimpleFieldType
case object FLOAT extends SimpleFieldType
case object DOUBLE extends SimpleFieldType
case object BOOL extends SimpleFieldType
case object STRING extends SimpleFieldType
case object DATETIME extends SimpleFieldType
sealed trait ComplexFieldType extends FieldType
case class LIST(fieldType: SimpleFieldType) extends ComplexFieldType
case class SET(fieldType: SimpleFieldType) extends ComplexFieldType
val field1: FieldType = INT
field1 match {
case FLOAT =>
case BOOL =>
case INT =>
case UINT =>
case DATETIME =>
case DOUBLE =>
case STRING =>
case LIST(_) =>
case SET(_) =>
}
ScalaC detect the non-exhaustiveness. I just had to use https://github.com/rtimush/sbt-rewarn#sbt-rewarn as the recompilation just skip it
I am currently using Enumeratum 1.5.13 in Scala 2.12.6. I have the following defined:
sealed abstract class PartOfSpeech(val value: Int) extends IntEnumEntry
case object PartOfSpeech extends IntEnum[PartOfSpeech] {
val values = findValues
case object Noun extends PartOfSpeech(0)
case object Adjective extends PartOfSpeech(1)
case object Verb extends PartOfSpeech(2)
case object Adverb extends PartOfSpeech(3)
case object Numeric extends PartOfSpeech(4)
case object Exclamation extends PartOfSpeech(5)
case object Preposition extends PartOfSpeech(6)
case object Pronoun extends PartOfSpeech(7)
case object Conjunction extends PartOfSpeech(8)
case object Determiner extends PartOfSpeech(9)
case object Article extends PartOfSpeech(10)
}
Then, when I attempt to use the withName() method like this:
val pos = PartOfSpeech.withName("Noun")
...I receive a compilation error indicating the method withName is not found. So, given I don't see a ScalaDoc for Enumeratum (at least I have not been able to find them), I don't know how to answer this without digging through its source code. Before investing time in that, I thought I might see if someone else has a simple and/or obvious solution.
What you are looking for was implemented on version 1.7.0 of Enumeratum.
you have 2 options to work with:
EnumEntry with "withName" function.
StringEnumEntry with "withValue" function.
In both ways you can get your needs
// Option 1:
sealed trait PartOfSpeech(val value: Int) extends EnumEntry
case object PartOfSpeech extends Enum[PartOfSpeech] {
val values = findValues
case object Noun extends PartOfSpeech(0)
case object Adjective extends PartOfSpeech(1)
case object Verb extends PartOfSpeech(2)
case object Adverb extends PartOfSpeech(3)
}
val pos = PartOfSpeech.withName("Noun") // return 0
// Option 2:
sealed trait PartOfSpeech(val value: String, val index: Int) extends StringEnumEntry
case object PartOfSpeech extends StringEnum[PartOfSpeech] {
val values = findValues
case object Noun extends PartOfSpeech("Noun", 0)
case object Adjective extends PartOfSpeech("Adjective", 1)
case object Verb extends PartOfSpeech("Verb", 2)
case object Adverb extends PartOfSpeech("Adverb", 3)
}
val pos = PartOfSpeech.withValue("None") // return 0
From what I can tell, the only way to make this work is for me to implement it myself within the case object. So, I added this:
private val enumEntryByClassSimpleNameLowerCase: Map[String, PartOfSpeech] =
values.map(enumEntry => (enumEntry.getClass.getSimpleName.takeWhile(_ != '$').toLowerCase, enumEntry)).toMap
def withName(value: String): Option[PartOfSpeech] =
enumEntryByClassSimpleNameLowerCase.get(value.toLowerCase)
It feels like a hack. I sure hope there's something inside of Enumeratum I am just missing. Please let me know if there is a better way to achieve this outcome. I use enums a whole bunch. So, this boilerplate is going to leak all over my codebase.
Not very familiar with Scala's type system, but here's what I'm trying to do.
I have a function that tries to filter people by first and last name, and if that fails filters by first name only.
case class Person(id: Int, first: String, last:String)
def(people: Set[Person], firstName: String, lastName: String): (MatchResult, Set[Person]) =
val (both, firstOnly) = people.filter(_.first == firstName).partition(_.last == lastName)
(both.nonEmpty, firstOnly.nonEmpty) match {
case (true, _) => (BothMatch, both)
case (false, true) => (FirstOnly, firstOnly)
case (_, _) => (NoMatch, Set[Person]())
}
Right now I am returning the filtered Set along with an Algebraic Data Type informing the caller which filter's results were used.
sealed trait MatchResult
case object BothMatch extends MatchResult
case object FirstOnly extends MatchResult
case object NoMatch extends MatchResult
However, returning a tuple of the Set + MatchResult doesn't present a very nice contract for the caller. I'm wondering how I can store my filtered results in my MatchResult.
I thought I could simply change to:
sealed trait MatchResult extends Set[People]
case object BothMatch extends MatchResult
case object FirstOnly extends MatchResult
case object NoMatch extends MatchResult
But the compiler tells me that I must implement abstract member iterator: Iterator[A]
I'm not sure if I should try to extend Set or somehow make MatchResult a case class that takes a set as a constructor argument.
One approach is to use case classes to store any matches as a member.
sealed trait MatchResult
case class BothMatch(results:Set[Person]) extends MatchResult
case class FirstOnly(results:Set[Person]) extends MatchResult
case object NoMatch extends MatchResult
In Scala, Set is is trait that has abstract members that must be implemented by any implementing class, and that's why you are receiving that error.
In your implementation, you could use these classes by,
(both.nonEmpty, firstOnly.nonEmpty) match {
case (true, _) => BothMatch(both)
case (false, true) => FirstOnly(firstOnly)
case (_, _) => NoMatch
}
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
I have a piece of code that matches on a case class and then invokes a function based on the type and an extracted value:
def resolveByType[T](ids: List[Any]) = ids map (id => resolver.resolve[T](id))
override def resolve(deferred: Vector[Deferred[Any]], ctx: Any): Vector[Future[Any]] = deferred flatMap {
case DeferAccounts(ids) => resolveByType[Account](ids)
case DeferLocations(ids) => resolveByType[Location](ids)
case DeferDelegates(ids) => resolveByType[EconomicUnit](ids)
case DeferMUs(ids) => resolveByType[MunicipalUnit](ids)
case _ =>
List(Future.fromTry(Try(List[Any]())))
}
The case classes are defined as follows
case class DeferAccounts(accounts: List[String]) extends Deferred[List[Option[Account]]]
case class DeferLocations(loctions: List[String]) extends Deferred[List[Option[Location]]]
case class DeferDelegates(delegates: List[String]) extends Deferred[List[Option[EconomicUnit]]]
case class DeferMUs(delegates: List[String]) extends Deferred[List[Option[MunicipalUnit]]]
As you can see, all I need is that inner type parameter and the list. I'm trying to figure out the most scala-y way to do this. Seems like a lot of boilerplate code right now. Is there a clean way to extract the list and type parameter programmatically instead of declaratively, as it's being done now, or is this the correct way to do this?