Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

For comprehension returning unexpected type with unused midstream assignment #7515

Open
scabug opened this issue May 24, 2013 · 4 comments
Open
Labels
Milestone

Comments

@scabug
Copy link

scabug commented May 24, 2013

scala> for ((k, v) <- Map("a" -> "b")) yield v -> k
res0: scala.collection.immutable.Map[String,String] = Map(b -> a)

scala> for ((k, v) <- Map("a" -> "b"); a = k.length) yield v -> k
res1: scala.collection.immutable.Map[String,String] = Map(b -> a)

But:

scala> for ((k, v) <- Map("a" -> "b"); a = k.length; b = v.length) yield v -> k
res2: scala.collection.immutable.Iterable[(String, String)] = List((b,a))

See scala-internals thread:

https://groups.google.com/forum/#!topic/scala-internals/Cmh0Co9xcMs

@scabug
Copy link
Author

scabug commented May 24, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7515?orig=1
Reporter: Erik Bruchez (ebruchez)
Affected Versions: 2.10.0, 2.10.1

@scabug
Copy link
Author

scabug commented May 24, 2013

@retronym said:
Another workaround:

scala> for ((k, v) <- Map("a" -> "b"); (a, b) = (k.length, v.length)) yield v -> k
res1: scala.collection.immutable.Map[String,String] = Map(b -> a)

@scabug scabug added the typer label Apr 7, 2017
@som-snytt som-snytt changed the title For comprehension returning unexpected type with unused assignation For comprehension returning unexpected type with unused midstream assignment Aug 5, 2021
@scala scala deleted a comment from scabug Aug 5, 2021
@SethTisue SethTisue added this to the Backlog milestone Aug 5, 2021
@SethTisue
Copy link
Member

not fixed in Scala 3: scala/scala3#16812

@joroKr21
Copy link
Member

When you consider that intermediate variables in for-comprehensions desugar to map calls with a tuple result (I don't see that changing in Scala 2), then it makes more sense. We can see the desugared code with reify:

import scala.reflect.runtime.universe._
println(reify(for ((k, v) <- Map("a" -> "b"); a = k.length; b = v.length) yield v -> k))
Expr[scala.collection.immutable.Iterable[(String, String)]](Predef.Map.apply(Predef.ArrowAssoc("a").$minus$greater("b")).withFilter(((check$ifrefutable$1) => check$ifrefutable$1: @unchecked match {
  case Tuple2((k @ _), (v @ _)) => true
  case _ => false
})).map(((x$2) => x$2: @unchecked match {
  case (x$1 @ Tuple2((k @ _), (v @ _))) => {
    val a = k.length();
    val b = v.length();
    Tuple3.apply(x$1, a, b)
  }
})).map(((x$3) => x$3: @unchecked match {
  case Tuple3(Tuple2((k @ _), (v @ _)), (a @ _), (b @ _)) => Predef.ArrowAssoc(v).$minus$greater(k)
})))

Of course the intermediate Tuple3 can't preserve the Map type. But even if it could I would argue that this is probably not what one intended. Map and Set for-comprehensions are tricky because preserving the collection type applies not only to the final result, but also intermediate results. But this will clump together for example in this case keys with the same length and you get a different number of elements out. Think of it like an hour glass where the sand can only go through the tight spot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants