DIfferent result of for/yield

31 views
Skip to first unread message

Tomek K.

unread,
Jan 9, 2017, 1:27:34 PM1/9/17
to scala-user
Can somebody explain me, please why there is a different type returned by these lines?


scala
> val a = Array(1,2,3,4,5)
a
: Array[Int] = Array(1, 2, 3, 4, 5)

scala
> for(i <- a) yield 2
res0
: Array[Int] = Array(2, 2, 2, 2, 2)

scala
> for(i <- 0 until a.length) yield 2
res1
: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 2, 2, 2, 2)


Why is there an Array type returned by first "for" loop and IndexedSeq/Vector by the second?

I tried similar example:

scala> class Car
defined class Car

scala
> val cars = Array(new Car, new Car, new Car, new Car, new Car)
cars
: Array[Car] = Array(Car@5527b211, Car@54cf7c6a, Car@78010562, Car@50756c76, Car@38aafb53)

scala
> for(car <- cars) yield new Car
res2
: Array[Car] = Array(Car@142213d5, Car@934b52f, Car@2630dbc4, Car@5ea4300e, Car@5a1c3cb4)

scala
> for(i <- 0 until cars.length) yield new Car
res3
: scala.collection.immutable.IndexedSeq[Car] = Vector(Car@2bfb583b, Car@73ae0257, Car@6fc1020a, Car@5762658b, Car@2629d5dc)


I thought these are just two ways of using "for" loop to go through a collection (like in C++ or Java - use "i" counter if you need to have an access to an index or use the second syntax if you need to do something on each element of a collection) but I don't understand why each of these calls produce different types (Array and IndexedSeq/Vector).

Thank you in advance

Lanny Ripple

unread,
Jan 9, 2017, 3:26:22 PM1/9/17
to scala-user
Scala desugars for/yield into flatMap and map calls (plus some others if you do pattern matching or assignment).  The Scala collections library, in general, returns the type you started with.  So if you for/yield with an Array you'll get back an Array.  The to/until method returns a Range.  The type a Range turns into when mapped over is an IndexedSeq.  (It's trivial to map a Range into something that isn't a Range which is why you don't get a Range back.)  Scala's Predef, which is included automatically in your programs, uses List by default for Seqs and Vector for IndexedSeqs.

scala> for (i <- (1 to 10).toArray) yield 2
res2: Array[Int] = Array(2, 2, 2, 2, 2, 2, 2, 2, 2, 2)



  -ljr

Axel Poigné

unread,
Jan 9, 2017, 3:28:11 PM1/9/17
to Tomek K., scala-user
The for-yield is in your case a shorthand for

val a = Array(1,2,3,4,5)
a.map(_ => 2)
(0 until a.length).map(_ => 2)
 
The second case is slightly more interesting in that 0 until a.length is a Range that obviously cannot be preserved by a map. If you look at the spec

class Range(val start: Int, val end: Int, val step: Int)
extends scala.collection.AbstractSeq[Int]
with IndexedSeq[Int]
with scala.collection.CustomParallelizable[Int, ParRange]
with Serializable
{…}

you see that the obvious super type candidate is an indexed sequence. 

Regards

Axel
Reply all
Reply to author
Forward
0 new messages