score:2

Accepted answer

using pattern matching for a simple isempty check is an abuse of pattern matching imho

if you do just want an isempty check, isempty/isdefined is perfectly fine. but in your case you also want to get the value. and using pattern matching for this is not abuse; it's precisely the basic use-case. using get allows to very easily make errors like forgetting to check isdefined or making the wrong check:

if(someoption.isempty){
  val value = someoption.get
  //some lines of code
} else{
  //some other lines
}

hopefully testing would catch it, but there's no reason to settle for "hopefully".

combinators (map and friends) are better than get for the same reason pattern matching is: they don't allow you to make this kind of mistake. choosing between pattern matching and combinators is a different question. generally combinators are preferred because they are more composable (as yuval's answer explains). if you want to do something covered by a single combinator, i'd generally choose them; if you need a combination like map ... getorelse, or a fold with multi-line branches, it depends on the specific case.

score:1

it seems similar to you in case of option but just consider the case of future. you will not be able to interact with the future's value after going out of future monad.

import scala.concurrent.executioncontext.implicits.global
import scala.concurrent.promise
import scala.util.{success, try}

// create a promise which we will complete after sometime
val promise = promise[string]();

// now lets consider the future contained in this promise
val future = promise.future;

val byget = if (!future.value.isempty) {
  val valtry = future.value.get
  valtry match {
    case success(v) => v + " :: added"
    case _ => "default :: added"
  }
}  else "default :: added"

val bymap = future.map(s => s + " :: added")

// promise was completed now
promise.complete(try("promise"))


//now lets print both values

println(byget)
// default :: added

println(bymap)
// success(promise :: added)

score:8

is there any objective advantages, or is it just personal preference?

i think there's a thin line between objective advantages and personal preference. you cannot make one believe there is an absolute truth to either one.

the biggest advantage one gains from using the monadic nature of scala constructs is composition. the ability to chain operations together without having to "worry" about the internal value is powerful, not only with option[t], but also working with future[t], try[t], either[a, b] and going back and forth between them (also see monad transformers).

let's try and see how using predefined methods on option[t] can help with control flow. for example, consider a case where you have an option[int] which you want to multiply only if it's greater than a value, otherwise return -1. in the imperative approach, we get:

val option: option[int] = generateoptionvalue

var res: int = if (option.isdefined) {
  val value = option.get
  if (value > 40) value * 2 else -1
} else -1

using collections style method on option, an equivalent would look like:

val result: int = option
  .filter(_ > 40)
  .map(_ * 2)
  .getorelse(-1)

let's now consider a case for composition. let's say we have an operation which might throw an exception. additionaly, this operation may or may not yield a value. if it returns a value, we want to query a database with that value, otherwise, return an empty string.

a look at the imperative approach with a try-catch block:

var result: string = _
try {
  val mayberesult = dangerousmethod()
  if (mayberesult.isdefined) {
    result = querydatabase(mayberesult.get)
  } else result = ""
}
catch {
  case nonfatal(e) => result = ""
}

now let's consider using scala.util.try along with an option[string] and composing both together:

val result: string = try(dangerousmethod())
  .tooption
  .flatten
  .map(querydatabase)
  .getorelse("")

i think this eventually boils down to which one can help you create clear control flow of your operations. getting used to working with option[t].map rather than option[t].get will make your code safer.

to wrap up, i don't believe there's a single truth. i do believe that composition can lead to beautiful, readable, side effect deferring safe code and i'm all for it. i think the best way to show other people what you feel is by giving them examples as we just saw, and letting them feel for themselves the power they can leverage with these sets of tools.


Related Query

More Query from same tag