svaens February 2016

Possible to make use of Scala's Option flatMap method more concise?

I'm admittedly very new to Scala, and I'm having trouble with the syntactical sugar I see in many Scala examples. It often results in a very concise statement, but honestly so far (for me) a bit unreadable.

So I wish to take a typical use of the Option class, safe-dereferencing, as a good place to start for understanding, for example, the use of the underscore in a particular example I've seen.

I found a really nice article showing examples of the use of Option to avoid the case of null.

https://medium.com/@sinisalouc/demystifying-the-monad-in-scala-cc716bb6f534#.fhrljf7nl

He describes a use as so:

trait User {
  val child: Option[User]
}

By the way, you can also write those functions as in-place lambda functions instead of defining them a priori. Then the code becomes this:

val result = UserService.loadUser("mike")
  .flatMap(user => user.child)
  .flatMap(user => user.child)

That looks great! Maybe not as concise as one can do in groovy, but not bad.

So I thought I'd try to apply it to a case I am trying to solve.

I have a type Person where the existence of a Person is optional, but if we have a person, his attributes are guaranteed. For that reason, there are no use of the Option type within the Person type itself.

The Person has an PID which is of type Id. The Id type consists of two String types; the Id-Type and the Id-Value.

I've used the Scala console to test the following:

class Id(val idCode : String, val idVal : String)

class Person(val pid : Id, val name : String)

val anId: Id = new Id("Passport_number", "12345")

val person: Person = new Pers        

Answers


Zoltán February 2016

Why do you insist on using flatMap? I'd just use map for your example instead:

val result = operson.map(_.pid).map(_.idVal).getOrElse("NoValue")

or even shorter:

val result = operson.map(_.pid.idVal).getOrElse("NoValue")

You should only use flatMap with functions that return Options. Your pid and idVals are not Options, so just map them instead.

You said

I have a type Person where the existence of a Person is optional, but if we have a person, his attributes are guaranteed. For that reason, there are no use of the Option type within the Person type itself.

This is the essential difference between your example and the User example. In the User example, both the existence of a User instance, and its child field are options. This is why, to get a child, you need to flatMap. However, since in your example, only the existence of a Person is not guaranteed, after you've retrieved an Option[Person], you can safely map to any of its fields.

Think of flatMap as a map, followed by a flatten (hence its name). If I mapped on child:

val ouser = Some(new User())
val child: Option[Option[User]] = ouser.map(_.child)

I would end up with an Option[Option[User]]. I need to flatten that to a single Option level, that's why I use flatMap in the first place.


Nyavro February 2016

If you looking for the most concise solution, consider this:

val result = operson.fold("NoValue")(_.pid.idVal)

Though one could find it not clear or confusing

Post Status

Asked in February 2016
Viewed 2,412 times
Voted 10
Answered 2 times

Search




Leave an answer