Is there any rational for Option not being Traversable?
In Scala 2.9, Seq(Set(1,3,2),Seq(4),Option(5)).flatten doesn’t compile and simply having it to implement the Traversable trait seams rational to me. If it’s not the case, there must be something I don’t see that don’t allow it. What is it?
PS: While trying to understand, I achieved awful things that compile, like:
scala> Seq(Set(1,3,2),Seq(4),Map("one"->1, 2->"two")).flatten
res1: Seq[Any] = List(1, 3, 2, 4, (one,1), (2,two))
PS2: I know I can write: Seq(Set(1,3,2),Seq(4),Option(5).toSeq).flatten or other ugly thing.
PS3: There seams to be work in the last month to make Option look more like Traversable without implementing it: commit, another commit
There may be challenges around having
flatMapreturn anOptionrather than aTraversable. Though that predates the whole 2.8CanBuildFrommachinery.The question was asked once before on the mailing list but didn’t elicit a response.
Here is an illustration:
The last line returns a
List("1!")instead ofOption. May be somebody can come up with aCanBuildFromthat would yield anSomeX("1!"). My attempt did not succeed:I need to pass the implicit explicitly:
Edit:
So I was able to work around the issue and have
SomeX(1).map(1+)return anOptionXby havingOptionXextendTraversableLike[A, OptionX[A]]and overridingnewBuilder.But then I get runtime errors on
SomeX(1) ++ SomeX(2)orfor (i <- SomeX(1); j <- List(1,2)) yield (i+j). So I don’t think it’s possible have option extendTraversableand do something sane in terms of returning the most specific type.Beyond feasibility, coding style wise, I’m not sure it’s a good thing to have
Optionbehave like aTraversablein all circumstances.Optionrepresent values that are not always defined, whileTraversabledefines methods for collections that can have multiple elements in it likedrop(n),splitAt(n),take(n),++. Although it would offer convenience ifOptionwas also aTraversable, I think it may make intent less clear.Using a
toSeqwhere necessary seems like a painless way to indicate that I want my option to behave like aTraversable. And for certain recurring use cases, there is theoption2Iterableimplicit conversion – so for instance this already works (they all returnList(1,2)):List(Option(1), Option(2), None).flattenfor (i <- List(0,1); j <- Some(1)) yield (i+j)Some(1) ++ Some(2)