Identifier shadowing in for-comprehensions is only supported in `flatMap`s
See original GitHub issueIn dotc 0.7.0, this compiles,
for {
x <- List(1, 2, 3)
x <- List(x + 1)
} yield x
but this does not,
for {
x <- List(1, 2, 3)
x = x + 1
} yield x
It gives the errors in the REPL,
<console>:14: error: recursive value x needs type
x = x + 1
^
<console>:14: error: x is already defined as value x
x = x + 1
^
It’s probably an accident of implementation, but it’s very useful for getting safe mutable-like syntax in long chained for-comprehensions, without needing to resort to introducing many different identifier names, provided every generator in the for-comprehension is a flatMap
, not a map
.
This is a quirk of Scala 2, and it would be nice to remove it in Scala 3.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:3
- Comments:19 (12 by maintainers)
Top Results From Across the Web
تويتر \ Lionel Parreaux (LParreaux@) - Twitter
Many programming languages in the OO tradition now support pattern matching ... Identifier shadowing in for-comprehensions is only supported in `flatMap`s ...
Read more >A Comprehensive Guide to For-Comprehension in Scala
Take a deep dive into Scala's for-comprehension construct.
Read more >Scala Standard Library 2.13.5 - scala.Option - Javadoc.io
final def flatMap[B](f: (A) => Option[B]): Option[B] ... Implicit conversion to Iterable[(A, B)] is also supported. ... Iterable in for comprehensions.
Read more >Scala Standard Library 2.13.3 - scala.Option
... to treat it as a collection or monad and use map , flatMap , filter , or foreach : ... flatMap —...
Read more >Introduction to Programming Languages - Jaemin Hong
classes are similar to classes but more convenient, e.g. automatic support for pretty printing and pattern matching. The syntax of a class definition...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I just wanted to add that Scala lacking shadowing of local variable is a huge usability problem IMHO. In functional languages like OCaml, where values are usually immutable, you can do:
In Scala, you have to come up with silly names that pollute the namespace:
…and in my experience, this is actually a huge source of mistakes. It is all too easy to write
println(name)
, forgetting about the more recent version of the value,nameCap
. This is especially terrible if you introduce the intermediate transformation in the middle of existing code, and you have to find and change all usages of the old version in the rest of the function. Shadowing actually helps users by preventing later code from seeing an obsolete binding.Now, it’s probably too late to change the scoping rules of Scala, but maybe something can be done to alleviate this usability hazard in a backward-compatible way. How about a syntax like this?
Then we can then say that for-comprehension bindings have the semantics of
new val
shadowing bindings instead of the semantics of simpleval
bindings (and we can make the desugaring itself actually usenew val
).@Sciss the argument is that inventing new names is hard, so at some point you’re going to use dummy names like
name0
,name1
etc. which is a big potential for mistakes (it’s easy to leave some reference toname2
instead ofname3
somewhere). Moreover, in the motivating example the new variable still conceptually represents thename
, even though the type is refined, so there is arguably no reason for picking a different name and polluting the local namespace.Anyway, at this point I guess it depends on individual preferences. Though I think it’s valuable to remember that ML programmers have been doing this for a long time without problems (AFAIK).