Skip to content

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Aug 26, 2025

Previously, we need to indent after the arrow, e.g.

xs.map: x =>
  x + 1

We now also allow to write the lambda on a single line:

xs.map: x => x + 1

The lambda extends to the end of the line.

This is a trial balloon to see whether anything breaks. If we want to pursue this it needs a SIP.

@soronpo
Copy link
Contributor

soronpo commented Aug 27, 2025

Will it also work for self types?

trait Foo: self =>
end Foo

@lihaoyi
Copy link
Contributor

lihaoyi commented Aug 27, 2025

I wonder if xs.map: case Some(x) => x + 1 could be made to work as well?

@som-snytt
Copy link
Contributor

The case for case is at #22016. I think the parens SIP opens the floodgates of consistency.

@lihaoyi
Copy link
Contributor

lihaoyi commented Aug 29, 2025

@odersky
Copy link
Contributor Author

odersky commented Aug 29, 2025

if we need a SIP for this, maybe we could fold it into https://contributors.scala-lang.org/t/sip-xx-allow-partial-function-literals-to-be-defined-with-parentheses/7207/16

Yes, I think the two go well together. This PR now also implements the single-case version of sip-xx. I have some reservations against admitting multiple cases between parentheses. I'll explain more on the SIP.

@odersky
Copy link
Contributor Author

odersky commented Aug 29, 2025

Will it also work for self types?

Right now, no. I'd like to re-think self types in general. So I'm not keen on fiddling with them until that's done.

Previously, we need to indent after the error, e.g.
```scala
xs.map: x =>
  x + 1
```
We now also allow to write the lambda on a single line:
```scala
xs.map: x => x + 1
```
The lambda extends to the end of the line.
@GLI-RK0
Copy link

GLI-RK0 commented Aug 29, 2025

Awesome. Will this extend to lambdas with by-name parameters and/or context parameters?

You can currently write

// after delay, execute fn
def delay(ms: Double)(fn: => Unit) = ???

delay(300):
  println("hello")

Will we also be able to write

def delay(ms: Double)(fn: => Unit) = ???

delay(300): println("hello")

and

def delay(ms: Double)(fn: (timestamp : Double) ?=> Unit) = ???

delay(300): println(s"time ${timestamp}")

?

@odersky odersky force-pushed the one-line-colon-lambda branch from b8b6a68 to e4a53c6 Compare August 29, 2025 13:18
@odersky
Copy link
Contributor Author

odersky commented Aug 29, 2025

Awesome. Will this extend to lambdas with by-name parameters and/or context parameters?

Currently, no. We should discuss what we want. Some choices:

  1. no extension to by-name or context-parameters
  2. allow : syntax for these parameters only
  3. allow : syntax for all arguments.

Possible reason for (2): The situation is similar to single-line-lambdas with parameters.
Possible reason for (3): We don't distincguish syntactically between by-name and by-value elsewhere.

@lihaoyi
Copy link
Contributor

lihaoyi commented Aug 29, 2025

If we allow delay(300): println("hello"), wouldn't we then have to allow println: "hello", and wouldn't println: "hello" be indistinguishable from a type ascription?

@GLI-RK0
Copy link

GLI-RK0 commented Aug 29, 2025

If we allow delay(300): println("hello"), wouldn't we then have to allow println: "hello", and wouldn't println: "hello" be indistinguishable from a type ascription?

Sorry I might be missing something, why would we have to allow println: "hello"? I was under the impression that : would only trigger an attempt to interpret the following rhs as a lambda when the parameter is typed as such? I assume that's what Martin meant by option 2?

@lihaoyi
Copy link
Contributor

lihaoyi commented Aug 29, 2025

Sure, println is not a higher order function, and delay(300): is. But do you know that information during parsing? Because this distinction between "this is a type ascription" and "this is a function taking a code block on the right" needs to happen super early even before typechecking happens.

If you don't like println, how about delay(300): "hello": is this a function call with a type ascription, or a function call taking two parameter lists?

@odersky
Copy link
Contributor Author

odersky commented Aug 29, 2025

@lihaoyi Yes, indeed. Allowing arbitrary expressions after: would conflict with type ascriptions. So I think we need to bury the idea.

@odersky
Copy link
Contributor Author

odersky commented Aug 29, 2025

I believe we have a problem with the new build. It does not pick up the scala-library changes in the bootstrapped build.
I see:

-- [E008] Not Found Error: tests/pos/closure-args.scala:1:29 -----------------------------------------------------------
1 |import language.experimental.relaxedLambdaSyntax
  |                             ^^^^^^^^^^^^^^^^^^^
  |                             value relaxedLambdaSyntax is not a member of object language.experimental

Yet, relaxedLambdaSyntax was added to language.experimental in the commit.

@@ -1,6 +1,6 @@
//> using options -rewrite -indent
//> nominally using scala 3.7.0-RC1
// does not reproduce under "vulpix" test rig, which enforces certain flag sets?
Copy link
Contributor

Choose a reason for hiding this comment

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

The reproduction was a parser crash instead of (some) error (only under -rewrite).

I haven't looked yet, but I wonder if it is worth trying to preserve the migration help (in 2025 almost '26)

parentheses are required around the parameter of a lambda

They can use copilot.

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