How to patten match on just the class, not the class attributes in Scala? - scala

I have some classes which sometimes have many many attributes, the classes are very large, so I don't want to turn the class into a case class.
However, I still want to be able to do a pattern match on the class type.
What I have been doing is the following:
object CourseSemester {
implicit val courseSemesterCase = (entity: CourseSemester)
=> { CourseSemesterCase(entity) }
case class CourseSemesterCase(entity: CourseSemester)
}
import CourseSemester._
class CourseSemester(val courses: List[Course],
val startDate: EventDate,
val endDate: EventDate,
val createdUpdatedBy: CreatedUpdatedBy,
... there are so many attributes... ) {
def totalCoursesInSemester: Int = courses.length
}
This allows me to do a match on a CourseSemester to the case class, so I can identify the class type in my pattern match. For example:
val c = new CourseSemester(...)
c match {
case CourseSemesterCase(a) => { }
case SomeOtherCase(b) => { }
}
Is this a reasonable way to do it, or is there a better way?

You may use Type Ascription
c match {
case cs : CourseSemester => // use cs
case s : SomeOther => // s is object of SomeOther type
}

Related

(Scala 2.12.8) pattern type is incompatible with expected type for parameterized type inside of parameterized class

(Scala 2.12.8)
Full Example
So lets say you have some "TypeEvidence" for some specific concrete types:
sealed trait TypeEvidence[+T]
object TypeEvidence{
case object DoubleType extends TypeEvidence[Double]
case object LongType extends TypeEvidence[Long]
case object StringType extends TypeEvidence[String]
}
I can match on those evidence objects like this:
object ThisIsOk{
def apply[T](ev: TypeEvidence[T]): Option[T] = {
ev match {
case TypeEvidence.DoubleType => Some(123.456)
case TypeEvidence.LongType => Some(1234L)
case _ => None
}
}
}
But not like this:
class ThisFails[T]{
def apply(ev: TypeEvidence[T]): Option[T] = {
ev match {
case TypeEvidence.DoubleType => Some(123.456)
case TypeEvidence.LongType => Some(1234L)
case _ => None
}
}
}
This fails to compile with:
pattern type is incompatible with expected type;
found : TypeEvidence.DoubleType.type
required: TypeEvidence[T]
pattern type is incompatible with expected type;
found : TypeEvidence.LongType.type
required: TypeEvidence[T]
Why is this? And how can this be worked around?
What if you do this with a type class?
class ThisFails[T]{
def apply(ev: TypeEvidence[T])(implicit
teto: TypeEvidenceToOption[T]
): Option[T] = teto(ev)
}
trait TypeEvidenceToOption[T] {
def apply(ev: TypeEvidence[T]): Option[T]
}
object TypeEvidenceToOption {
implicit val double: TypeEvidenceToOption[Double] =
{ case TypeEvidence.DoubleType => Some(123.456) }
implicit val long: TypeEvidenceToOption[Long] =
{ case TypeEvidence.LongType => Some(1234L) }
implicit def default[T]: TypeEvidenceToOption[T] = _ => None
}
new ThisFails[Double].apply(TypeEvidence.DoubleType) // Some(123.456)
new ThisFails[Long].apply(TypeEvidence.LongType) // Some(1234)
new ThisFails[String].apply(TypeEvidence.StringType) // None
I'm not entirely sure why it didn't work the way you expected. The only reasonable explanation I tell to myself is that the compiler has no issue using T as a placeholder for any type while T belongs to the parameterized method, whereas when it belongs to a parameterized class, it's more restrictive in terms of what you can do with it.
As a workaround, you can use .type and .asIstanceOf:
class ThisFails[T] {
def apply(ev: TypeEvidence[T]): Option[T] = {
ev match {
case _: TypeEvidence.DoubleType.type => Some(123.456.asInstanceOf[T])
case _: TypeEvidence.LongType.type => Some(1234L.asInstanceOf[T])
case _ => None
}
}
}
val x = new ThisFails[Long]
val x2 = new ThisFails[Double]
val x3 = new ThisFails[String]
println(x.apply(TypeEvidence.LongType)) // Some(1234)
println(x2.apply(TypeEvidence.DoubleType)) // Some(123.456)
println(x3.apply(TypeEvidence.StringType)) // None
I'm aware it's not nice, but you asked for a workaround. This pattern match now matches an object of the given type. Of course, with this workaround, having the objects "caseable" is redundant now.
I had a peek at the disassembled code of object ThisIsOk to figure out this workaround:
public static class ThisIsOk$
{
public static final ThisIsOk$ MODULE$;
static {
ThisIsOk$.MODULE$ = new ThisIsOk$();
}
public <T> Option<T> apply(final Main.TypeEvidence<T> ev) {
Object module$;
if (Main.TypeEvidence$.DoubleType$.MODULE$.equals(ev)) {
module$ = new Some((Object)BoxesRunTime.boxToDouble(123.456));
}
else if (Main.TypeEvidence$.LongType$.MODULE$.equals(ev)) {
module$ = new Some((Object)BoxesRunTime.boxToLong(1234L));
}
else {
module$ = None$.MODULE$;
}
return (Option<T>)module$;
}
}
I saw here the way pattern match works is by calling equals on their types, but since equals is not overridden, what this actually does is a reference check. Recall:
// in Object.java file:
public boolean equals(Object obj) {
return (this == obj);
}
Also I saw a cast to Option<T> in the end.
So with these observations, the class ThisFails[T] workaround I just showed earlier gets disassembled into this:
public static class ThisFails<T>
{
public Option<T> apply(final Main.TypeEvidence<T> ev) {
Object module$;
if (Main.TypeEvidence$.DoubleType$.MODULE$ == ev) {
module$ = new Some((Object)BoxesRunTime.boxToDouble(123.456));
}
else if (Main.TypeEvidence$.LongType$.MODULE$ == ev) {
module$ = new Some((Object)BoxesRunTime.boxToLong(1234L));
}
else {
module$ = None$.MODULE$;
}
return (Option<T>)module$;
}
}
Which is almost identical to the object ThisIsOk's disassembled code, except for using == instead of equals, which does not matter in this case, as I explained earlier.
I tested it with both Scala 2.13.8 and your version here on Scastie, and both worked.

Scala pattern matching type with inherited classes

I have a series of inherited classes,with some more methods than the base class. Like this:
class Animal
{
var Name: String
}
class Fish extends Animal
{
def swim()
{
println("I'm a Fish and i'm swimming!");
}
}
class Turtle extends Animal
{
def swim()
{
println("I'm a Turtle and i'm swimming!");
}
}
I would like to use the type match pattern to a generic Animal class, to recognize the exact type and apply the swim() method if it can, like this:
myAnimal match {
case m:Fish => m.Swim()
case m:Turtle => m.Swim()
case _: => doSomethingElse()
}
I would like to write it in an elegant way, avoiding to repeat continuously the lines.
I know that I can do this:
myAnimal match {
case (_:Fish | _:Turtle) => println("I can do this!")
}
And I know, as I wrote above, that I can do:
myAnimal match {
case m:Fish => m.swim()
}
but, I can't put them in or, like this
myAnimal match {
case (m:Fish | m:Turtle) => m.swim() //ERROR (cannot recognize swim() method)
//Not even this
case m # (_:Fish | _:Turtle) => m.swim() //ERROR (cannot recognize swim() method)
case _: => doSomethingElse()
}
A good solution would be to insert an intermediate class, like AnimalsThatCanSwim that extend Animals. This solution should be the last option, because I have to avoid changing the extended classes.
You can use structural types combined with an extractor that uses reflection to check if your object has a swim method. Thanks to Mateusz Kubuszok and Dmytro Mitin, I now have a solution that seems to work.
Use like this:
myAnimal match {
case CanSwim(m) => m.swim()
case _ => println("Boohoo, I can't swim!")
}
The other stuff:
import scala.reflect.runtime.universe._
type CanSwim = { def swim(): Unit }
object CanSwim {
def unapply(arg: Any): Option[CanSwim] = {
try {
var res: Option[CanSwim] = None
for (symb <- runtimeMirror(arg.getClass.getClassLoader)
.reflect(arg)
.symbol
.info
.member(TermName("swim")) //get all methods named swim
.asTerm
.alternatives) { //alternatives because it might be overloaded
if (symb.isMethod) {
val msymb = symb.asMethod
//Check if the signature matches (Returns Unit and has 1 empty parameter list)
if (msymb.returnType =:= typeOf[Unit] && msymb.paramLists == List(List()))
res = Some(arg.asInstanceOf[CanSwim])
}
}
res
} catch {
case _ => None
//Might want to change this, but I don't think it's necessary to handle or throw exceptions
//If it failed, it probably means it can't swim
}
}
}
Link to Scastie
However, I really wouldn't recommend it. It's probably just easier to refactor your code.
<script src="https://scastie.scala-lang.org/gFBe7jTQQiW3WnPVTJoFPw.js"></script>

How to write a custom decoder for [Option[Option[A]] in Circe?

I had written a Reads converter in play-json for Option[Option[A]] that had the following behavior:
//given this case class
case class MyModel(field: Option[Option[String]])
//this JSON -- maps to --> this MyModel:
//"{ \"field\": \"value\" }" --> MyModel(field = Some(Some("value")))
//"{ \"field\": null, ... }" --> MyModel(field = Some(None))
//"{ }" --> MyModel(field = None)
So, providing the value mapped to Some[Some[A]], providing null mapped to Some[None] (i.e. Some[Option.empty[A]]), and not providing the value mapped to just None (i.e. Option.empty[Option[A]]). Here's the play-json converter:
def readOptOpt[A](implicit r: Reads[A]): Reads[Option[Option[A]]] = {
Reads[Option[Option[A]]] { json =>
path.applyTillLast(json).fold(
identity,
_.fold(_ => JsSuccess(None), {
case JsNull => JsSuccess(Some(None))
case js => r.reads(js).repath(path).map(a => Some(Some(a)))
})
)
}
}
Now I am converting my play-json code to Circe, but I can't figure out how to write a Decoder[Option[Option[A]] that has the same behavior. That is, I need
def optOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]] = ??? //help!
Any ideas on how I can make this work? Thanks
I figured this out:
There were two problems:
1) How to deal with the case where the field was completely missing from the JSON. Turns out you have to use Decoder.reattempt in your custom decoder, following Circe's decodeOption code, which works.
2) How to have the compiler recognize cases of Option[Option[A]] when your decoder code is sitting in a helper object (or wherever). Turns out if you're using semi-auto derivation, you can create an implicit in the companion object and that will override the defaults:
//companion object
object MyModel {
implicit def myModelOptOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]]] =
MyHelperObject.optOptDecoder
implicit val myModelDecoder: Decoder[MyModel] = deriveDecoder
}
Anyway, I don't think this will be much help to anybody in the future, so unless I get any upvotes in the next few hours I think I'll just delete this.
Edit2: Okay it was answered so I won't delete it. Stay strong, esoteric circe question, stay strong...
An Option[Option[A]] is a bit odd. I understand and mostly agree with the reasoning, but I think it's weird enough that it may warrant just replacing it with your own class (and writing a decoder for that). Something like:
sealed trait OptionalNull[+A] {
def toOption: Option[Option[A]]
}
object NotPresent extends OptionalNull[Nothing] {
override def toOption = None
}
object PresentButNull extends OptionalNull[Nothing] {
override def toOption = Some(None)
}
case class PresentNotNull[A](value: A) extends OptionalNull[A] {
override def toOption = Some(Some(value))
}
This has the additional benefit of not having to worry about implicit precedence and stuff like that. Might simplify your decoder.
Here is another solution I found (This is not my gist):
sealed trait UpdateOrDelete[+A]
case object Delete extends UpdateOrDelete[Nothing]
final case class UpdateOptionalFieldWith[A](value: A) extends UpdateOrDelete[A]
object UpdateOrDelete {
implicit def optionalDecoder[A](implicit decodeA: Decoder[A]): Decoder[UpdateOptionalField[A]] =
Decoder.withReattempt {
// We're trying to decode a field but it's missing.
case c: FailedCursor if !c.incorrectFocus => Right(None)
case c =>
Decoder.decodeOption[A].tryDecode(c).map {
case Some(a) => Some(UpdateOptionalFieldWith(a))
case None => Some(Delete)
}
}
// Random UUID to _definitely_ avoid collisions
private[this] val marker: String = s"$$marker-${UUID.randomUUID()}-marker$$"
private[this] val markerJson: Json = Json.fromString(marker)
implicit def optionalEncoder[A](implicit encodeA: Encoder[A]): Encoder[UpdateOptionalField[A]] =
Encoder.instance {
case Some(Delete) => Json.Null
case Some(UpdateOptionalFieldWith(a)) => encodeA(a)
case None => markerJson
}
def filterMarkers[A](encoder: Encoder.AsObject[A]): Encoder.AsObject[A] =
encoder.mapJsonObject { obj =>
obj.filter {
case (_, value) => value =!= markerJson
}
}
}

How do you write a json4s CustomSerializer that handles collections

I have a class that I am trying to deserialize using the json4s CustomSerializer functionality. I need to do this due to the inability of json4s to deserialize mutable collections.
This is the basic structure of the class I want to deserialize (don't worry about why the class is structured like this):
case class FeatureValue(timestamp:Double)
object FeatureValue{
implicit def ordering[F <: FeatureValue] = new Ordering[F] {
override def compare(a: F, b: F): Int = {
a.timestamp.compareTo(b.timestamp)
}
}
}
class Point {
val features = new HashMap[String, SortedSet[FeatureValue]]
def add(name:String, value:FeatureValue):Unit = {
val oldValue:SortedSet[FeatureValue] = features.getOrElseUpdate(name, SortedSet[FeatureValue]())
oldValue += value
}
}
Json4s serializes this just fine. A serialized instance might look like the following:
{"features":
{
"CODE0":[{"timestamp":4.8828914447482E8}],
"CODE1":[{"timestamp":4.8828914541333E8}],
"CODE2":[{"timestamp":4.8828915127325E8},{"timestamp":4.8828910097466E8}]
}
}
I've tried writing a custom deserializer, but I don't know how to deal with the list tails. In a normal matcher you can just call your own function recursively, but in this case the function is anonymous and being called through the json4s API. I cannot find any examples that deal with this and I can't figure it out.
Currently I can match only a single hash key, and a single FeatureValue instance in its value. Here is the CustomSerializer as it stands:
import org.json4s.{FieldSerializer, DefaultFormats, Extraction, CustomSerializer}
import org.json4s.JsonAST._
class PointSerializer extends CustomSerializer[Point](format => (
{
case JObject(JField("features", JObject(Nil)) :: Nil) => new Point
case JObject(List(("features", JObject(List(
(feature:String, JArray(List(JObject(List(("timestamp",JDouble(ts)))))))))
))) => {
val point = new Point
point.add(feature, FeatureValue(ts))
point
}
},
{
// don't need to customize this, it works fine
case x: Point => Extraction.decompose(x)(DefaultFormats + FieldSerializer[Point]())
}
))
If I try to change to using the :: separated list format, so far I have gotten compiler errors. Even if I didn't get compiler errors, I am not sure what I would do with them.
You can get the list of json features in your pattern match and then map over this list to get the Features and their codes.
class PointSerializer extends CustomSerializer[Point](format => (
{
case JObject(List(("features", JObject(featuresJson)))) =>
val features = featuresJson.flatMap {
case (code:String, JArray(timestamps)) =>
timestamps.map { case JObject(List(("timestamp",JDouble(ts)))) =>
code -> FeatureValue(ts)
}
}
val point = new Point
features.foreach((point.add _).tupled)
point
}, {
case x: Point => Extraction.decompose(x)(DefaultFormats + FieldSerializer[Point]())
}
))
Which deserializes your json as follows :
import org.json4s.native.Serialization.{read, write}
implicit val formats = Serialization.formats(NoTypeHints) + new PointSerializer
val json = """
{"features":
{
"CODE0":[{"timestamp":4.8828914447482E8}],
"CODE1":[{"timestamp":4.8828914541333E8}],
"CODE2":[{"timestamp":4.8828915127325E8},{"timestamp":4.8828910097466E8}]
}
}
"""
val point0 = read[Point]("""{"features": {}}""")
val point1 = read[Point](json)
point0.features // Map()
point1.features
// Map(
// CODE0 -> TreeSet(FeatureValue(4.8828914447482E8)),
// CODE2 -> TreeSet(FeatureValue(4.8828910097466E8), FeatureValue(4.8828915127325E8)),
// CODE1 -> TreeSet(FeatureValue(4.8828914541333E8))
// )

Is there a best practice to assign a value to a scala Option when it's not initialized/None?

I have the following class where the properties are an Option[T]
class User extends IdBaseEntity[UUID] {
var id: Option[UUID] = None
var name: Option[String] = None
var createdOn: Option[Date] = None
}
In some data access layer I need to assign these properties if they aren't set before the object is persisted to cassandra. Here are a few ways for the createdOn property. Are any of these the best approach or is there something better I should be doing?
Example 1
entity.createdOn = Some(entity.createdOn.map(identity).getOrElse(new Date()))
Example 2
entity.createdOn = entity.createdOn.orElse(Some(new Date()))
Example 3
entity.createdOn = entity.createdOn match {
case None => Some(new Date())
case _ => entity.createdOn
}
Example 4
entity.createdOn = entity.createdOn match {
case None => Some(new Date())
case Some(x) => Some(x)
}
Example 5
entity.createdOn match {
case None => entity.createdOn = Some(new Date())
case _ =>;
}
Matching on Option is not really idiomatic (IMHO). I prefer to get orElse or getOrElse. Personally I would go with example 2.
I'm not sure whether this will fit your use case, but it is more idiomatic to make User an immutable case class:
case class User(id: Option[UUID] = None, ...)
and copy it, rather than updating the fields in-place:
val updatedEntity = entity.copy(name = user.name.orElse(Some("Chris")))
I'd consider changing your design a bit - for two reasons:
It looks like the User class should be read-only once initialized, so something like a case class or val instead of var would capture that requirement:
case class User( id:UUID, name:String, createdOn:Date );
It looks like every User is required to have an id, name, and createdOn property set, so Option[] is not a good way to model that.
I often setup a Builder class along side read-only classes to
simplify and decouple the object-construction process from
what the object represents - something like
this
object User {
class Builder {
var id:UUID = UUID.randomUUID()
def id( v:UUID ):this.type = {id =v; this; }
var name:String = id.toString
def name( v:String ):this.type = { name=v; this; }
var createdOn:Date = new Date()
def createdOn( v:Date ):this.type = { createdOn = v; this; }
def build():User = {
assert( Seq(id,name,createdOn).find( _ == null ).isEmpty, "Must set all props" )
User( user, name, createdOn )
}
}
}
Anyway - that's another way to do things ...
Since the scenario is "get a property value and update it if some condition holds", I'd try to encapsulate access to properties. For example:
/**
* Read+write access to property `P` of object `R`.
*/
case class Accessor[R,P](get: R => P, set: (R, P) => Unit) {
/** Utility for updating values. */
def update(record: R, modfn: P => P) =
set(record, modfn(get(record)));
}
class User {
var id: Option[Int] = None;
}
object User {
// For each property of `User` we need to define an accessor,
// but this is one time job:
val idA: Accessor[User,Option[Int]] =
Accessor((u: User) => u.id,
(u: User, r: Option[Int]) => u.id = r);
}
object Test {
import User._;
// We can do a lot of stuff now with accessors, for example set
// default values for `Option[...]` ones:
def setDefault[A,B](record: A,
accessor: Accessor[A,Option[B]],
defPropVal: => B) =
accessor.update(record, _.orElse(Some(defPropVal)));
val user = new User();
// Set user's id, if not defined:
setDefault(user, idA, 42);
}
So instead of defining a specific method for each property for filling in default values, we define a generic accessor for each property. Then we can use them to implement all the other stuff generically.