Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Option GenTraversableOnce?

Tags:

scala

I am confused. In TraversableLike, there is a function flatMap with the signature

flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): Iterable[B]

However, I can use it this way

scala> Iterable(1,2,3,4,5).flatMap{i=>if (i%2==0) {None} else {Some(i)}}
res1: Iterable[Int] = List(1, 3, 5)

Why is it possible? How is Option converted to GenTraversableOnce? It doesn't seem like a subclass...

like image 606
Karel Bílek Avatar asked Jul 11 '12 09:07

Karel Bílek


3 Answers

As you can see in the class diagram(*), Option is not a subclass of GenTraversableOnce, but there's a implicit conversion available to Iterable, which is a GenTraversableOnce.

enter image description here

(*) Yeah, ok, I cheated. Class diagrams are not available on Scaladoc yet... but they should be tomorrow! :-)

like image 76
Daniel C. Sobral Avatar answered Oct 19 '22 20:10

Daniel C. Sobral


There is in fact an implicit conversion by default from Some[X] to GenTraversableOnce[X]. This is very simple to test in the REPL

scala>  implicitly[Function[Some[Int],GenTraversableOnce[Int]]]
res1: Some[Int] => scala.collection.GenTraversableOnce[Int] = <function1>

scala> implicitly[Some[Int] => GenTraversableOnce[Int]] // alternative syntax
res2: Some[Int] => scala.collection.GenTraversableOnce[Int] = <function1>

And in fact this is defined in the object Option. Inside scala package:

object Option {
  /** An implicit conversion that converts an option to an iterable value
   */
  implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList

  /** An Option factory which creates Some(x) if the argument is not null,
   *  and None if it is null.
   *
   *  @param  x the value
   *  @return   Some(value) if value != null, None if value == null
   */
  def apply[A](x: A): Option[A] = if (x == null) None else Some(x)

  /** An Option factory which returns `None` in a manner consistent with
   *  the collections hierarchy.
   */
  def empty[A] : Option[A] = None
}

option2Iterable is exactly what you are looking for. You can also see why when testing in your REPL you could see that the implementation of GenTraversableOnce is a list.

If you are looking for implicit conversions which are automatically imported without you doing anything ( like the one you can see in the REPL using implicitly) you have to look at:

  • Predef.scala
  • Companion objects of the class
like image 17
Edmondo1984 Avatar answered Oct 19 '22 20:10

Edmondo1984


It seems like it is indeed implicitly converted to List.

scala> val l:scala.collection.GenTraversableOnce[Int] = Some(3)
l: scala.collection.GenTraversableOnce[Int] = List(3)

scala> val l:scala.collection.GenTraversableOnce[Int] = None
l: scala.collection.GenTraversableOnce[Int] = List()

personal note: scala magic implicit conversions are sometimes really confusing.

like image 3
Karel Bílek Avatar answered Oct 19 '22 21:10

Karel Bílek