0

I'm working with a lot of Option and I need to use pattern match/case almost every call to check if object is None or not.

Is possible to write cleaner code when you use a lot of match cases?

def process(schema: Option[String], body: String, token:String, queueInfo: Map[String, String]) = {
  jsonSchemaService.findByDescriptionFromCache(schema) match {
    case Some(jsonSchema) =>
      jsonSchema.schema match {
        case Some(s) =>
          val ku = buildKinesisUtils(token, queueInfo)
          validateAndPublish(body, s, ku)
        case None =>
          Future(Left(SchemaNotDefinedException(s"O Json schema [$schema] não possui um schema definido")))
      }
    case None =>
      Future(Left(SchemaNotFoundException("Não foi possível encontrar o JsonSchema informado")))
  }
}
0

3 Answers 3

2

use .map and .flatMap to avoid pattern matching on Options:

jsonSchemaService
    .findByDescriptionFromCache(schema)
    .map { jsonSchema =>
      jsonSchema.schema.map { s =>
        val ku = buildKinesisUtils(token, queueInfo)
        validateAndPublish(body, s, ku)
      }.getOrElse(Future(Left(SchemaNotDefinedException(s"O Json schema [$schema] não possui um schema definido"))))
    }.getOrElse(Future(Left(SchemaNotFoundException("Não foi possível encontrar o JsonSchema informado"))))

Note: it's a bit hard to produce a correct answer without knowing the signature of all methods used...but it should be somehow close to what you'd want

Sign up to request clarification or add additional context in comments.

4 Comments

Basically, I would like to return a Future[Either[Throwable, String]] but i was writing a lot of match/case. Looks like a java code.
methods like Option.map, Option.flatMap, Future.map/flatMap and Future.recover / Future.recoverWith may be useful in this type of cases
Nice! And what is the best approach using Either[Left, Right]?
I would recommend you to read nojokescala.eu/post/future-either. if you still need any help, just let us know
1

Using pattern matching isn't really an idiomatic way of dealing with options. It's better to use the methods like map and flatmap and take advantage of for comprehensions to work with options. If you are checking everytime if an option is None, it's not much better than a null check.

Since your methods are returning Options but you actually want Eithers you can convert these options to Eithers using the toRight method.

def process(schema: Option[String], body: String, token:String, queueInfo: Map[String, String]) = {
     val res = for {
        jsonSchema <- jsonSchemaService.findByDescriptionFromCache(schema).toRight(SchemaNotFoundException("Não foi possível encontrar o JsonSchema informado")).right
        s <- jsonSchema.schema.toRight(SchemaNotDefinedException(s"O Json schema [$schema] não possui um schema definido")).right
      } yield s
    res.fold(e => Future(Left(e)), s => validateAndPublish(body, s, buildKinesisUtils(token, queueInfo)))
}

As of scala 2.12, Either is Right-Biased by default so the .right calls are no longer needed.

4 Comments

@placplacboom Then the final result is Future(Left(SchemaNotFoundException)). The operation is fail-fast. Once you get a Left that Left is returned and none of the other operations run. The last line we transform the either, the left side gets wrapped in a Future(Left) so that it has the correct type, if it's a Right (the success case) we pass the result to your function. This way, you code only really needs to deal with the success case at each step.
my bad, I've deleted the other comment. I was asking about object Either[Throwable, String]. Is possible to .right on Either?
Nvm! .fold does the job :) Thanks
.right exists only on Either, and is only necessary pre-Scala 2.12. If you are using the latest scala version you can just leave that part out. Before scala 2.12, both sides of Either were considered "equal" by the library, Right was only considered the success case by convention. the .right method transforms the Either into a RightProjection which is basically an either where Right is success and Left is Failure. In new versions of scala it's unneeded because that's already the default behavior.
0

What you're doing is actually a fold.

option.fold(noneCase)(s => someCase(s))

Comments