DEfine scala enum with 2 properties - scala

I have several fields that i want to create enum from but those fields have 2 values: Valid and Not valid:
object MyEnum extends Enumeration
{
val
type1, // this type is valid
type2, // valid
type3, // valid
type4, // Not valid
type5, // Not valid
type6, // Not valid
type7 // Not valid
= value
}
Any suggestion how to distinguish between Valid and Not valid via code ? or maybe it must separate into 2 enums ?

You can create a function on the Enum object and use the .toString part of Enumeration.Value
object MyEnum extends Enumeration {
val type1 = Value("valid")
val type2 = Value("valid")
val type3 = Value("valid")
val type4 = Value("Not valid")
val type5 = Value("Not valid")
val type6 = Value("Not valid")
val type7 = Value("Not valid")
lazy val lookup = this.values.map { n => (n, n.toString == "valid") }.toMap
def isValid(myEnum: MyEnum.Value) = lookup.getOrElse(myEnum, false)
}
MyEnum.isValid(MyEnum.type1) //> res0: Boolean = true
MyEnum.isValid(MyEnum.type7) //> res1: Boolean = false
Sources:
https://github.com/scala/scala/blob/v2.11.7/src/library/scala/Enumeration.scala#L146
http://www.scala-lang.org/api/current/#scala.Enumeration$Value

There's a different pattern you could use that does not extend Enumeration but acts similarly:
object MyEnum extends Serializable {
abstract sealed class MyEnum(
val ordinal: Int, val isValid: Boolean
) extends Ordered[MyEnum] with Serializable {
def compare(that: MyEnum) = that.ordinal compare this.ordinal
def toInt: Int = this.ordinal
}
case object Type1 extends MyEnum(0, true)
case object Type2 extends MyEnum(1, true)
case object Type3 extends MyEnum(2, true)
case object Type4 extends MyEnum(3, false)
case object Type5 extends MyEnum(4, false)
case object Type6 extends MyEnum(5, false)
case object Type7 extends MyEnum(6, false)
def fromInt(i: Int): MyEnum = values.find(_.ordinal == i).get
val values = Set(
Type1, Type2, Type3, Type4, Type5, Type6, Type7
)
}
This way you are able to assign in a way like val myEnum: MyEnum.MyEnum = MyEnum.Type1 similar to your example above and you will have access to myEnum.isValid. Similarly you can access it ordinally with the fromInt method. Such as MyEnum.fromInt(0).isValid. If you provide some more context on what you're trying to do with the values I may be able to provide a better solution. Hope this helps.

Related

how to map many strings to integer values in Scala?

I have the following use case. User is providing two kinds of strings type and growth I need to convert the value of each into an integer from a known map and return the sum of both value.
What I did to map the strings is:
object Types extends Enumeration {
val T1 = 5
val T2 = 6
// list of values is really long!
val TYPE1 = "type1"
val TYPE2 = "type2"
}
object Growth extends Enumeration {
val G1 = 1
val G2 = 10
// list of values is really long!
val GROWTH1 = "growth1"
val GROWTH2 = "growth2"
}
Now consider user is calling sum("type1", "growth2") the expected output is 15 because 5+10=15
I wrote this skeleton function but I'm having trouble utilizing the enumeration objects. How can I do this without having so many if/else?
def sum(type: String, growth: String) : Int = {
var sum:Int = 0
????
return sum
}
if my approach is flawed I'm happy to try another
scala.Enumeration doesn't let you use syntax like this
object MyEnum extends Enumeration {
val value = "string"
}
It actually requires you to do something more like
object MyEnum extends Enumeration {
val value = Value("string")
}
and then you are passing not String but MyEnum.Value.
Since you are giving up on passing around Strings (at least in Scala 2, in Scala 3 you have an option to use type MyEnum = "value1" | "value2" and/or opaque type MyEnum), you create a sealed hierarchy instead
sealed abstract class Type(
val name: String,
val number: Int
) extends Product with Serializable
object Type {
case object Type1 extends Type("type1", 5)
case object Type2 extends Type("type2", 6)
}
sealed abstract class Growth(
val name: String,
val number: Int
) extends Product with Serializable
object Growth {
case object Growth1 extends Growth("growth1", 1)
case object Growth2 extends Growth("growth2", 10)
}
def sum(`type`: Type, growth: Growth) : Int =
`type`.number + growth.number
If you needed to construct a collection of all possible values, instead of scala.Enumeration you can use Enumeratum library instead
import enumeratum.values._
// IntEnumEntry and IntEnum specialize for Int
// and it allows to eliminate boxing
// The Int has to be defined as `val value: Int`
// findValues has to called so that the compiler
// can find all instances in the compile-time and
// populate the `values` collection
// Enumeratum then generate a lot of useful methods out of
// this list e.g. `withName` to find enum by its name
sealed abstract class Type(
val value: Int
) extends IntEnumEntry
object Type extends IntEnum[Type] {
case object Type1 extends Type(5)
case object Type2 extends Type(6)
val values = findValues
}
sealed abstract class Growth(
val value: Int
) extends IntEnumEntry
object Growth extends IntEnum[Growth] {
case object Growth1 extends Growth(1)
case object Growth2 extends Growth(10)
val values = findValues
}
def sum(`type`: Type, growth: Growth) : Int =
`type`.value + growth.value
This can be done by create a Map that gives the score for each String:
val scoreMap = Map(
"type1" -> 5,
"type2" -> 6,
"growth1" -> 1,
"growth2" -> 10,
)
The score can then be computed using foldLeft:
def score(strings: List[String]) =
strings.foldLeft(0){ case (sum, str) => sum + scoreMap.getOrElse(str, 0) }
score(List("type1", "growth2")) // 15
Values that are missing from the Map have the default value 0.
You can extend the class Val of Enumeration class.
Example:
object Types extends Enumeration {
final case class Pairing (label: String, value: Int) extends Val (value, label)
val TYPE1 = Pairing ("type1", 5)
val TYPE2 = Pairing ("type2", 6)
}
object Growths extends Enumeration {
final case class Pairing (label: String, value: Int) extends Val (value, label)
val GROWTH1 = Pairing ("growth1", 1)
val GROWTH2 = Pairing ("growth2", 10)
}
type Type = Types.Pairing
type Growth = Growths.Pairing
def sum(t: Type, g: Growth) = t.id + g.id
// usage:
import Types._
import Growths._
println(sum(TYPE1, GROWTH2)) // => 15
If you wish to use the operator + and reuse the val names :
object Types extends Enumeration {
final case class Entry (value: Int) extends Val (value) {
def +(g: Growth) = id + g.id
}
val type1 = Entry (5)
val type2 = Entry (6)
}
object Growths extends Enumeration {
final case class Entry (value: Int) extends Val (value) {
def +(t: Type) = t.id + id
}
val growth1 = Entry (1)
val growth2 = Entry (10)
}
type Type = Types.Entry
type Growth = Growths.Entry
// usage:
import Types._
import Growths._
println(type1 + growth2) // => 15
println(growth1 + type2) // => 7
println(growth1) // => "growth1"

Changing implicit value in scala response of nested object

I have a controller
def getCars(notation: Option[Boolean] = Some(false)) = identified.auth(hasOceanScope).async { implicit request =>
carService.getCars().map {
case Seq() => Response.NotFound
case cars => Response.Ok(cars)
}
}
Car case class looks like this:
case class Car(
name: String,
createdAt: LocalDateTimeOffset,
wheels: Seq[Wheel]
)
object Car{
implicit val wheelFormat = Wheel.format
implicit def toOffset(date: LocalDateTime): LocalDateTimeOffset = LocalDateTimeOffset.apply(date)
implicit val format = Json.format[Car]
case class Wheel(
name: String,
createdAt: LocalDateTimeOffset
)
object Wheel{
implicit val format = Json.format[Wheel]
implicit def toOffset(date: LocalDateTime): LocalDateTimeWithOffset = LocalDateTimeWithOffset.apply(date)
)
When notation query parameter is true -> want to return createdAt Car object and Wheel object field with notation => 2022-10-22T00:00:00#1
When notation query parameter is false -> want to return createdAt Car object and Wheel object field without notation => 2022-10-22T00:00:00
That is why I have create two formats in LocalDateTimeOffset object
case class LocalDateTimeWithOffset(dt: LocalDateTime, offset: Int) {
val localDateTimeWithOffsetReads: Reads[LocalDateTimeWithOffset] = Reads.of[String].flatMap {
str => if (str.contains("#")) {
val (dt, offset) = str.splitAt(str.indexOf("#"))
Reads.pure(LocalDateTimeWithOffset(LocalDateTime.parse(dt), offset.drop(1).toInt))
} else {
Reads.pure(LocalDateTimeWithOffset(LocalDateTime.parse(str), 1))
}
}
val localDateTimeWithOffsetWrites: Writes[LocalDateTimeWithOffset] = new Writes[LocalDateTimeWithOffset] {
override def writes(a: LocalDateTimeWithOffset): JsValue = JsString(a.dt.format(dateTimeUTCFormatter) + s"#${a.offset}")
}
val localDateTimeWithOffsetWritesOff: Writes[LocalDateTimeWithOffset] = new Writes[LocalDateTimeWithOffset] {
override def writes(a: LocalDateTimeWithOffset): JsValue = JsString(a.dt.format(dateTimeUTCFormatter))
}
val localDateTimeWithoutOffsetFormat: Format[LocalDateTimeWithOffset] = Format(localDateTimeWithOffsetReads, localDateTimeWithOffsetWritesOff)
val localDateTimeWithOffsetFormat: Format[LocalDateTimeWithOffset] = Format(localDateTimeWithOffsetReads, localDateTimeWithOffsetWrites)
implicit var format: Format[LocalDateTimeWithOffset] = localDateTimeWithoutOffsetFormat
}
But how can I use two different formats from controller based on notation query parameter value?
Well just looking at your question's title, changing implicit value is not something you would see Scala developers do, because compiler is responsible to lookup for implicit values, and you would definitely want to avoid ambiguous implicits found error. instead, you see developers using something so called type class instance constructor or something similar. This is how it works in your case:
Assuming you have a class A, which can be formatted to/from Json in many ways:
case class A(field1: String) // could have more fields
object A {
val formatFirstApproach: Format[A] = ???
val formatSecondApproach: Format[A] = ???
// note that the above instances are not implicit
def getFormat(somePredicate: Boolean): Format[A] = {
// input parameters can be anything, these are the parameters you need,
// in order to be able to decide which instance to return
if (somePredicate) formatFirstApproach else formatSecondApproach
}
}
And then, given a class B which has an instance variable of type A in it, you can use the type class instance constructor:
case class B(a: A, field2: Int)
object B {
// this is the type class instance constructor, since it constructs an instance of a type class (Format in this case)
implicit def format(implicit aFormatter: Format[A]): Format[B] = Json.format
}
And the thing is, you probably would not care about the serialization unless in the controller layer, so in the controller layer you can do:
def someApi(flag: Boolean) = Action async { req =>
implicit val aFormatter = A.getFormat(flag) // that's it, you don't need to mention anything more anywhere
businessLogic().map {
case Seq() => Response.NotFound
case cars => Response.Ok(Json.toJson(cars))
}
}

How to create more specific types for String and other data types while creating domain models

While domain modeling how can I ensure that two types — User and Place don't interchange their name fields, which are of type String.
trait User {
val firstName: String
val lastName: String
}
object User {
final class Live(val firstName: String,val lastName: String) extends User
def apply(firstName: String, lastName: String): User = new Live(firstName, lastName)
}
trait Place {
val name: String
}
object Place {
final class Live(val name: String) extends Place
def apply(name: String): Place = new Live(name)
}
val a = User("Tushar", "Mathur")
val b = Place("Mumbai")
val c = Place(a.firstName)
// How do I disable this ^
This is supported in Scala as in the example below. There are some libraries that can reduce boilerplate but I'm just showing the simplest option:
// define more restrictive String-like types. AnyVal construction can be free from
// overhead with some caveats.
case class UserName(name: String) extends AnyVal
case class PlaceName(name: String) extends AnyVal
// define your classes (I've changed them a bit for brevity):
case class User(name: UserName)
case class Place(name: PlaceName)
// implicits for convenience of construction:
implicit val strToUserName = UserName(_)
implicit val strToPlaceName = PlaceName(_)
// test it out:
scala> val u = User("user")
u: User = User(UserName(user))
scala> val p = Place("place")
p: Place = Place(PlaceName(place))
// as expected you CAN'T do this:
scala> User(p.name)
<console>:17: error: type mismatch;
found : PlaceName
required: UserName
User(p.name)
^
// comparison test:
scala> p.name == u.name
<console>:16: warning: comparing case class values of types PlaceName and UserName using `==' will always yield false
p.name == u.name
^
res3: Boolean = false
// you can still get at the string value:
scala> p.name
res6: PlaceName = PlaceName(place)
scala> p.name.name
res5: String = place

How can I create an instance of a Case Class with constructor arguments with no Parameters in Scala?

I'm making a Scala app that sets by reflection field values. This works OK.
However, in order to set field values I need a created instance. If I have a class with an empty constructor, I can do this easily with classOf[Person].getConstructors....
However, when I try doing this with a Case class with a non empty constructor It doesn't work. I have all of the field names and its values, as well as the Object type I need to create. Can I instance the Case Class somehow with what I've got?
The only thing I don't have is the parameter names from the Case Class constructor or a way to create this without parameter and then setting the values via reflection.
Let's go to the example.
I have the following
case class Person(name : String, age : Int)
class Dog(name : String) {
def this() = {
name = "Tony"
}
}
class Reflector[O](obj : O) {
def setValue[F](propName : String, value : F) = ...
def getValue(propName : String) = ...
}
//This works
val dog = classOf[Dog].newInstance()
new Reflector(dog).setValue("name", "Doggy")
//This doesn't
val person = classOf[Person].newInstance //Doesn't work
val ctor = classOf[Person].getConstructors()(0)
val ctor.newInstance(parameters) //I have the property names and values, but I don't know
// which of them is for each parameter, nor I name the name of the constructor parameters
If you are looking for a way to instantiate the object with no arguments, you could do the same as you did in your example, just so long as your reflection setter can handle setting the immutable vals.
You would provide an alternate constructor, as below:
case class Person(name : String, age : Int) {
def this() = this("", 0)
}
Note that the case class will not generate a zero-arg companion object, so you will need to instantiate it as: new Person() or classOf[Person].newInstance(). However, that should be what you are looking to do.
Should give you output like:
scala> case class Person(name : String, age : Int) {
| def this() = this("", 0)
| }
defined class Person
scala> classOf[Person].newInstance()
res3: Person = Person(,0)
The case class should have default args, so that you can just Person(); in the absence of a default arg, supplying a null for name might (or ought to) hit a require(name != null).
Alternatively, use reflection to figure out which params have defaults and then supply nulls or zeros for the rest.
import reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
// case class instance with default args
// Persons entering this site must be 18 or older, so assume that
case class Person(name: String, age: Int = 18) {
require(age >= 18)
}
object Test extends App {
// Person may have some default args, or not.
// normally, must Person(name = "Guy")
// we will Person(null, 18)
def newCase[A]()(implicit t: ClassTag[A]): A = {
val claas = cm classSymbol t.runtimeClass
val modul = claas.companionSymbol.asModule
val im = cm reflect (cm reflectModule modul).instance
defaut[A](im, "apply")
}
def defaut[A](im: InstanceMirror, name: String): A = {
val at = newTermName(name)
val ts = im.symbol.typeSignature
val method = (ts member at).asMethod
// either defarg or default val for type of p
def valueFor(p: Symbol, i: Int): Any = {
val defarg = ts member newTermName(s"$name$$default$$${i+1}")
if (defarg != NoSymbol) {
println(s"default $defarg")
(im reflectMethod defarg.asMethod)()
} else {
println(s"def val for $p")
p.typeSignature match {
case t if t =:= typeOf[String] => null
case t if t =:= typeOf[Int] => 0
case x => throw new IllegalArgumentException(x.toString)
}
}
}
val args = (for (ps <- method.paramss; p <- ps) yield p).zipWithIndex map (p => valueFor(p._1,p._2))
(im reflectMethod method)(args: _*).asInstanceOf[A]
}
assert(Person(name = null) == newCase[Person]())
}
The approach below works for any Scala class that has either a no-arg ctor or has an all defaulted primary ctor.
It makes fewer assumptions than some others about how much information is available at the point of call as all it needs is a Class[_] instance and not implicits etc. Also the approach does not rely on the class having to be a case class or having a companion at all.
FYI During construction precedence is given to the no-arg ctor if present.
object ClassUtil {
def newInstance(cz: Class[_ <: AnyRef]): AnyRef = {
val bestCtor = findNoArgOrPrimaryCtor(cz)
val defaultValues = getCtorDefaultArgs(cz, bestCtor)
bestCtor.newInstance(defaultValues: _*).asInstanceOf[A]
}
private def defaultValueInitFieldName(i: Int): String = s"$$lessinit$$greater$$default$$${i + 1}"
private def findNoArgOrPrimaryCtor(cz: Class[_]): Constructor[_] = {
val ctors = cz.getConstructors.sortBy(_.getParameterTypes.size)
if (ctors.head.getParameterTypes.size == 0) {
// use no arg ctor
ctors.head
} else {
// use primary ctor
ctors.reverse.head
}
}
private def getCtorDefaultArgs(cz: Class[_], ctor: Constructor[_]): Array[AnyRef] = {
val defaultValueMethodNames = ctor.getParameterTypes.zipWithIndex.map {
valIndex => defaultValueInitFieldName(valIndex._2)
}
try {
defaultValueMethodNames.map(cz.getMethod(_).invoke(null))
} catch {
case ex: NoSuchMethodException =>
throw new InstantiationException(s"$cz must have a no arg constructor or all args must be defaulted")
}
}
}
I ran into a similar problem. Given the ease of using Macro Paradise, Macro Annotations are a solution (for scala 2.10.X and 2.11 so far).
Check out this question and the example project linked in the comments below.

How do I create an enum in scala that has an extra field

In Java I have something like this
public enum FlatFileHeaderMapping {
HEADER_EL(1),
HEADER_RESERVED1(5),
HEADER_RESERVED2(2),
HEADER_MESSAGE_TYPE(4)
public final int fieldSize;
private FlatFileHeaderMapping(int fieldSize) {
this.fieldSize = fieldSize;
}
}
which I can then use it place each line into a map and later access the keys in the map via this enum (like symbols)
Enumeration does not have this quality as far as I can see, and case classes are not ordered like the enum declarations - so cannot be used to match a record layout as shown above. At least not without the support of an ordered collection.
I could be missing something obvious, hence the question!
Thanks
Ray
overthink is right, but there's a less verbose way of declaring the case objects:
sealed abstract class FlatFileHeaderMapping(val fieldSize: Int)
case object HEADER_EL extends FlatFileHeaderMapping(1)
case object HEADER_RESERVED1 extends FlatFileHeaderMapping(5)
case object HEADER_RESERVED2 extends FlatFileHeaderMapping(2)
case object HEADER_MESSAGE_TYPE extends FlatFileHeaderMapping(4)
You could try using case objects:
sealed trait FlatFileHeaderMapping { val fieldSize: Int }
case object HEADER_EL extends FlatFileHeaderMapping { val fieldSize = 1 }
case object HEADER_RESERVED1 extends FlatFileHeaderMapping { val fieldSize = 5 }
case object HEADER_RESERVED2 extends FlatFileHeaderMapping { val fieldSize = 2 }
case object HEADER_MESSAGE_TYPE extends FlatFileHeaderMapping { val fieldSize = 4 }
You can then use the enum like so:
object Test {
def foo(x: FlatFileHeaderMapping) {
val result =
x match {
case HEADER_EL => "it's a HEADER_EL!"
case other => "its field size is: " + other.fieldSize
}
println(result)
}
def main(args: Array[String]) {
foo(HEADER_EL)
foo(HEADER_MESSAGE_TYPE)
}
}
The main nicety you get here is compile-time checking that all enum values are handled. i.e in the x match { ... } code above you'd get a compile error if you didn't have the 'case other => ...` clause in there.
I'm pretty much just restating this answer, which lists pros and cons of this approach.
object Direction extends Enumeration {
val North = Value("North")
val East = Value("East")
val South = Value("South")
val West = Value("West")
}
scala> import Direction._
scala> values foreach println
scala> val map = HashMap(North -> 1, South -> 2)
This is answered in Enumeration with constructor and lookup table
A simpler solution exist for integer value:
object FlatFileHeaderMapping extends Enumeration {
type FlatFileHeaderMapping = Value
val HEADER_EL = Value(1, "HEADER_EL")
val HEADER_RESERVED1 = Value(5, "HEADER_RESERVED1")
val HEADER_RESERVED2 = Value(2, "HEADER_RESERVED2")
val HEADER_MESSAGE_TYPE = Value(4, "HEADER_MESSAGE_TYPE")
}
Reproducing the contents of the accepted answer, as it's hidden behind a broken Tumblr link (that I accessed via Archive.org), which in turn points to this page.
trait Enum { //DIY enum type
import java.util.concurrent.atomic.AtomicReference //Concurrency paranoia
type EnumVal <: Value //This is a type that needs to be found in the implementing class
private val _values = new AtomicReference(Vector[EnumVal]()) //Stores our enum values
//Adds an EnumVal to our storage, uses CCAS to make sure it's thread safe, returns the ordinal
private final def addEnumVal(newVal: EnumVal): Int = { import _values.{get, compareAndSet => CAS}
val oldVec = get
val newVec = oldVec :+ newVal
if((get eq oldVec) && CAS(oldVec, newVec)) newVec.indexWhere(_ eq newVal) else addEnumVal(newVal)
}
def values: Vector[EnumVal] = _values.get //Here you can get all the enums that exist for this type
//This is the trait that we need to extend our EnumVal type with, it does the book-keeping for us
protected trait Value { self: EnumVal => //Enforce that no one mixes in Value in a non-EnumVal type
final val ordinal = addEnumVal(this) //Adds the EnumVal and returns the ordinal
def name: String //All enum values should have a name
override def toString = name //And that name is used for the toString operation
override def equals(other: Any) = this eq other.asInstanceOf[AnyRef]
override def hashCode = 31 * (this.getClass.## + name.## + ordinal)
}
}
//And here's how to use it, if you want compiler exhaustiveness checking
object Foos extends Enum {
sealed trait EnumVal extends Value /*{ you can define your own methods etc here }*/
val F = new EnumVal { val name = "F" }
val X = new EnumVal { val name = "X" }
}
/**
scala> Foos.values.find(_.name == "F")
res3: Option[Foos.EnumVal] = Some(F)
scala> Foos.X.ordinal
res4: Int = 1
scala> def doSmth(foo: Foos.EnumVal) = foo match {
case Foos.X => println("pigdog")
}
<console>:10: warning: match is not exhaustive!
missing combination $anon$1
missing combination $anon$2
scala> def doSmth(foo: Foos.EnumVal) = foo match {
case Foos.X => println("pigdog")
case Foos.F => println("dogpig")
}
doSmth: (foo: Foos.EnumVal)Unit
**/
//But if you don't care about getting exhaustiveness warnings, you can do:
object Foos extends Enum {
case class EnumVal private[Foos](name: String) extends Value /* { you can define your own methods and stuff here } */
val F = EnumVal("F")
val X = EnumVal("X")
}
/**
Which is a bit less boilerplatey.
Cheers,
√
**/