When creating a collection inside Option each attempt to make the next member of the collection may fail, which will also lead to the failure of the collection as a whole. After the first refusal to make a member, I would like to immediately refuse and return None for the entire collection. What is the idiomatic way to do this in Scala?
Here is one approach I came up with:
def findPartByName(name: String): Option[Part] = . . . def allParts(names: Seq[String]): Option[Seq[Part]] = names.foldLeft(Some(Seq.empty): Option[Seq[Part]]) { (result, name) => result match { case Some(parts) => findPartByName(name) flatMap { part => Some(parts :+ part) } case None => None } }
In other words, if any findPartByName call returns None , allParts returns None . Otherwise, allParts returns a Some containing a collection of Parts , all of which are guaranteed. The empty collection is fine.
The above has the advantage that after the first failure it stops calling findPartByName . But foldLeft once for each name, independently.
Here is the version that is reset as soon as findPartByName returns None :
def allParts2(names: Seq[String]): Option[Seq[Part]] = Some( for (name <- names) yield findPartByName(name) match { case Some(part) => part case None => return None } )
Currently, I believe that the second version is more readable, but (a) what seems to be the most readable is likely to change, as I gain more experience with Scala, (b) I get the impression that early return disapproving of Scala and (c) none of them does what is happening especially obvious to me.
The combination of "all or nothing" and "rejection of the first rejection" seems like such a basic programming concept, I believe that for its expression there should be a common Scala or functional idiom.