TransWikia.com

elegant way of extracting option value when need it

Stack Overflow Asked by user804968 on November 7, 2021

I have an object that had an optional field on it, and on certain point of my code I need to have this field, so I did something like this:

  def updateReport(task: Task): Future[Task] = for {
      taskResponse <- Future {
        task.response.getOrElse(throw NoExpectedFieldsException(s"expected to have Response for taskId: ${task.taskId}"))
      }
      res <- reportService.updateReportWithResponse(taskResponse) map (_ => task)
    } yield res

task looks something like:

Task(taskId: String, ... , response: Option[Response])

is there a more elegant way of doing that?

thought maybe to add function:

  private def extractOpt[T](elem: Option[T]) = {
    elem.getOrElse(throw NoExpectedFieldsException(s"expected to have element"))
  }

but that just moves the ugliness somewhere else…

Task is a case class I created to be able to create differet type of tasks, it has a field called taskType that determain which type of task it is, and all the required elements are on the task as options

One Answer

Option forms a monad so we can map over it

def updateReport(task: Task): Future[Task] = {
  task.response.map { taskResponse =>
    reportService.updateReportWithResponse(taskResponse).map(_ => task)
  }.getOrElse(Future.failed(new NoExpectedFieldsException(s"expected to have Response for taskId: ${task.taskId}")))
}

Option is an algebraic data type so we can pattern match on it

def updateReport(task: Task): Future[Task] = {
  task.response match {
    case None => 
      Future.failed(new NoExpectedFieldsException(s"expected to have Response for taskId: ${task.taskId}"))
      
    case Some(taskResponse) => 
      reportService.updateReportWithResponse(taskResponse).map(_ => task)
  }
}

Option can also be folded to a pure value, as Luis suggests,

def updateReport(task: Task): Future[Task] = {
  task.response.fold(
    Future.failed[Task](new NoExpectedFieldsException(s"expected to have Response for taskId: ${task.taskId}"))
  ) { taskResponse =>
    reportService.updateReportWithResponse(taskResponse).map(_ => task)
  }
}

Option can represent a non-existent value, and for that purpose extracting pure value out of it is an unsafe operation so it is probably a good idea to have unsafe operations appear uglier in code to discourage or make visible their use

task.response.getOrElse(throw NoExpectedFieldsException(s"expected to have Response for taskId: ${task.taskId}"))

Answered by Mario Galic on November 7, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP