1

I tried following two versions of code to understand how yield in scala works. I am unable to understand why I am getting two different results

In this version, I call yield and the expression is simply multiply by 2. I get a Vector of 1st 10 multiples of 2. It makes sense to me

scala> val r = for (j <- 1 to 10) yield {
     | (j*2).toString //multiply by 2
     | }
r: scala.collection.immutable.IndexedSeq[String] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) // got multiples of 2. This looks ok

Interestingly in this version, all I have done is store the multiplication by 2 in a val. But now I get an empty vector! Why is this?

scala> val r = for (j <- 1 to 10) yield {
     | val prod = (j*2).toString //multiply by 2 but store in a val
     | }
r: scala.collection.immutable.IndexedSeq[Unit] = Vector((), (), (), (), (), (), (), (), (), ())  //this is empty

I thought that maybe the val prod = (j*2).toString results in a Unit result but when I try following independent expression on scala interpreter, I can see that prod is a String

scala> val prod = 2.toString()
prod: String = 2
Manu Chadha
  • 15,555
  • 19
  • 91
  • 184
  • 1
    You need to return something from the lamba - your lambda does not return anything - it is therefore a `void` type or `Unit` in Scala. Add `prod` on a line after the `val` and it will implicitly be returned. – Boris the Spider Aug 11 '16 at 07:59
  • @BoristheSpider is right. `val prod` is created and abandoned 10 times so the `yield` has nothing to yield after each iteration. – jwvh Aug 11 '16 at 08:30
  • To put it another way, `prod` is indeed a string, but `val prod = ...` is of type `Unit`. So the Vector in the second example is of type Vector[Unit]. – wwkudu Aug 11 '16 at 09:02
  • in your second statement, you need to add `prod` after the last line for it to serve as the return value. All you are doing in the last line is set a value but return nothing, hence the `Unit` output. – jtitusj Aug 11 '16 at 09:07

1 Answers1

0

In Scala every expression return something. But assignments are designed to return Unit for performance reasons (see What is the motivation for Scala assignment evaluating to Unit rather than the value assigned?).

In your snippet, in last example REPL says prod: String = 2, meaning that prod has some value, that's done for your convenience. But try { val prod = 2.toString() }:

scala> { val prod = 2.toString() }

scala> println(res0)
()

() is the only possible value of Unit type.

(I'm not sure why res0 was not shown after first like, because resN-like values in REPL collect all non-assigned explicitly results)

dveim
  • 3,381
  • 2
  • 21
  • 31