Skip to content

allow forEach as an alternative to foreach #15368

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

Closed

Conversation

AugustNagro
Copy link
Contributor

We have some problems with foreach in Scala:

1. Compatibility with Java libraries

import java.util.List

for x <- List.of(1,2,3) do println(x)

This doesn't work, since Java uses forEach on its collections. It's annoying that Java collections work in for-yield loops, but not for-do.

2. Developer Expectations

Developers expect forEach, not foreach, because the former is camel cased just like flatMap and every other method. Java, JavaScript, C++, Kotlin, and the majority of popular languages case foreach according to the language's regular style.

I propose that in cases where foreach is required but not resolved, we try forEach as an alternative.

This fixes the compatibility issue, while also allowing developers to use the case they prefer.

Questions:

  1. Should this behavior be limited to non-Scala sources?
  2. Should this behavior be limited to for-do loop desugaring?
  3. Are there binary compatibility issues to consider?

@som-snytt
Copy link
Contributor

It would be something if lowercase identifiers were allowed to match ignoring case.

Other names I would always write lowercase for this reason: classpath for classPath and filesystem for fileSystem. Also typecheck.

The rule would apply for any member lookup, including for override checking.

TIL the word "literal" can refer to a typo in a single letter, so I'd propose calling the language feature language.literals. Then everyone would quickly learn the alternative meaning of "literal".

Under language.literals, we would no longer see the warning about class names differing only in case on case-insensitive file systems. (That would be a CaseInsensitiveFileSystem.)

@TheElectronWill
Copy link
Contributor

TheElectronWill commented Jun 4, 2022

Supporting for without extensions (at least in its simple form, without any flatMap nor filter) with java constructs would be practical. But IMHO allowing two different ways to declare foreach is a bad idea. Scala isn't case insensitive (thankfully!) and it would be weird to introduce exceptions like foreach/forEach. It would also introduce the need to check that only one of foreach/forEach is defined (and what about overrides?)

If we want to support for loops with Java collections, it should be restricted to for loops.

@ritschwumm
Copy link

why not just use an extension method on java collections providing foreach?

or even better (if you ignore some minor sideeffects for the ecosystem): just rename foreach to forEach in general ;)

@AugustNagro
Copy link
Contributor Author

why not just use an extension method on java collections providing foreach?

That's a good idea, the problem I see is that it confuses users, who see both forEach and foreach in their IDE autocomplete and don't know which one to choose.

Supporting for without extensions (at least in its simple form, without any flatMap nor filter) with java constructs would be practical. But IMHO allowing two different ways to declare foreach is a bad idea.

That makes sense to me. Do you have an idea on how to implement? for-loop desugaring to foreach is done in the parse phase, so the information is lost by the type phase. I have a hacky idea but I imagine there's a better way.

Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think the right way to treat this is with an extension method.

@TheElectronWill
Copy link
Contributor

That makes sense to me. Do you have an idea on how to implement? for-loop desugaring to foreach is done in the parse phase, so the information is lost by the type phase. I have a hacky idea but I imagine there's a better way.

Actually, it's the typer that calls desugar.apply, which turns for into foreach and all (see here). It could check whether the symbol is(JavaDefined) and call forEach instead of foreach.

An extension method on Java collections would work, of course. If it's not in Predef it would require an import, though.

@AugustNagro
Copy link
Contributor Author

Thanks Will & Martin; I created #15379 which defines 2 extension methods in stdLibPatches/Predef.scala

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

Successfully merging this pull request may close these issues.

5 participants