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

require parens around lambda argument with type annotation #12218

Closed
adriaanm opened this issue Nov 5, 2019 · 13 comments
Closed

require parens around lambda argument with type annotation #12218

adriaanm opened this issue Nov 5, 2019 · 13 comments

Comments

@adriaanm
Copy link
Contributor

adriaanm commented Nov 5, 2019

{ x: Any => } looks confusingly like a self-type; write { (x: Any) => ... } instead.

@dwijnand
Copy link
Member

dwijnand commented Nov 5, 2019

I wonder how much of corpus would stop compiling with this. Is there any other motivation over "looks similar"?

@smarter
Copy link
Member

smarter commented Nov 5, 2019

You can omit the parens when the lambda is wrapped in a block but not when it's wrapped in parens, you also cannot omit them when the lambda has more than one parameter, so it's a very limited special case. According to Martin it also complicates the parser quite a bit.

@smarter
Copy link
Member

smarter commented Nov 5, 2019

I've made a PR to stop IntelliJ from wanting to remove these parens: JetBrains/intellij-scala#488

@neko-kai
Copy link

I fear the body of code that uses this syntax in the wild is far too large (to be precise: nearly all Scala code) – without a scalafix rule at the very least the migration will not be tenable

@SethTisue
Copy link
Member

SethTisue commented Nov 12, 2019

note that there is an open proposal to change how self-types are expressed: scala/scala3#7374

@som-snytt
Copy link

som-snytt commented Jan 1, 2020

Self-types look annoyingly like lambdas.

Edit: i.e., this is very common case and looks so clean it would be criminal to get rid of it. Just exercising my right to vote.

@lihaoyi
Copy link

lihaoyi commented Feb 24, 2020

I'm just going to chip in and say that if named self types and lambdas are too similar, we can just ban named self types. Un-named self types { this: Foo => are entirely unambiguous, and if you want to assign it a name private[this] def thing = this is not a huge hardship.

This similarity also isn't limited to named self types: any named self reference like object Foo{ bar => } is similarly hard to parse, both by humans and programmatically by e.g. ScalaParse.

There are probably 3-4 orders of magnitude more lambdas than there are named self-references out there in the wild; making lambdas more verbose in exchange for preserving the conciseness of named self-references is backwards

@som-snytt
Copy link

I don't often boo outright, but I noticed this is already encoded ("enshrined"):

scala> List(1,2,3).map { i => i + 1 }
val res1: List[Int] = List(2, 3, 4)

scala> List(1,2,3).map { i: Int => i + 1 }
1 |List(1,2,3).map { i: Int => i + 1 }
  |                  ^^^^^^
  |parentheses are required around the parameter of a lambda
  |This construct can be rewritten automatically under -language:Scala2Compat -rewrite.

Where is @tpolecat our community advocate or liaison or guy we trust, whatever his role, when you really need him?

Please don't let them put parens back in. There should be a monitor that ensures that the paren count decreases monotonically.

Now I'm going to plant a "Parsers for the People!" sign on the lawn by the curb. Then the HOA will take it down because I don't even have my own lawn to plant a flag.

@tpolecat
Copy link

tpolecat commented Mar 2, 2020

@som-snytt I don't feel strongly but I think I would prefer that the number of special cases decrease monotonically. In any case I had never noticed the splendid error message you get when you try to put parens around a self-type.

@ trait Foo { (this: Any) => } 
(console):1: not a legal formal parameter.
Note: Tuples cannot be directly destructured in method or function parameters.
      Either create a single parameter accepting the Tuple1,
      or consider a pattern matching anonymous function: `{ case (param1, param1) => ... }
trait Foo { (this: Any) => }
                 ^

@martijnhoekstra
Copy link

@tpolecat paulp wants to talk about your feelings: #1564

@SethTisue
Copy link
Member

If someone wants to implement a warning for this under -Xsource:3, I think that would be accepted. In Scala 2, I don't think we should otherwise warn here.

@SethTisue SethTisue transferred this issue from scala/scala-dev Nov 6, 2020
@SethTisue SethTisue added this to the Backlog milestone Nov 6, 2020
@som-snytt
Copy link

som-snytt commented Jan 20, 2024

This happens as a warning under the scala 3 migration scheme. I can't try out the latest -X options because the PR hasn't been fully reviewed yet by @SethTisue oh IIRC it's -Xsource:3migration to warn, -Xsource:3cross to error as shown.

And hey, it's quick-fixable!

Do I have to edit my excellent SO answer on this parser question? I never saw it as a special case, but a consequence of Scala being a scalable language, in the sense that the scales fall from your eyes.

➜  snips scala -Xsource:3
Welcome to Scala 2.13.12 (OpenJDK 64-Bit Server VM, Java 21).
Type in expressions for evaluation. Or try :help.

scala> List(42).map { i: Int => i + 1 }
                       ^
       error: parentheses are required around the parameter of a lambda
       Use '-Wconf:msg=lambda-parens:s' to silence this warning. [quickfixable]
       Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings.
       Applicable -Wconf / @nowarn filters for this fatal warning: msg=<part of the message>, cat=scala3-migration

scala>

scala/scala#10327

@som-snytt
Copy link

@tpolecat also anything from pre-pandemic qualifies as retro-computing!

scala> trait Foo { (this: Any) => }
                   ^
       error: self-type annotation may not be in parentheses

oh also, just to show that when the Lord slams one door in your face, etc,

scala> List(42).map(implicit (i: Int) => implicitly[Int] + 1)
val res0: List[Int] = List(43)

@SethTisue SethTisue modified the milestones: Backlog, 2.13.13 Jan 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants