Skip to content

SIP-44 - Fewer braces #45

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

Merged
merged 5 commits into from
Aug 26, 2022
Merged

SIP-44 - Fewer braces #45

merged 5 commits into from
Aug 26, 2022

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Jul 1, 2022

No description provided.

@julienrf julienrf changed the title Fewer braces SIP SIP-44 - Fewer braces Jul 1, 2022
Copy link

@gabro gabro left a comment

Choose a reason for hiding this comment

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

I've read the proposal and (tried to) read all the related discussions on the contributors forum.

I've written Scala for 10 years, and I haven't had a chance to write a lot of code with the new indentation style, so I still have mixed feelings about the whole thing.

That said, taking optional braces as they are today as a starting point, I agree they would feel unfinished without this last bit of syntax, so I'm overall ✅ on this proposal.

One thing that came out during the contributors discussion is how this would look in case of multiple block parameters, like with groupMap or groupMapReduce from the standard library.

@odersky, since I don't see it mentioned in the proposal document here, nor in the documentation, what's the recommended syntax for handling multiple block parameters? Or in that case we would still recommend braces?

Either way, I think it would make sense to mention that case in the proposal.

@sjrd
Copy link
Member

sjrd commented Jul 9, 2022

I've not been assigned to this SIP, but I had already done quite a bit of "reviewing" back in May. So I'll just link to the main post where I laid down my findings:
https://contributors.scala-lang.org/t/make-fewerbraces-available-outside-snapshot-releases/5024/23?u=sjrd

@odersky
Copy link
Contributor Author

odersky commented Jul 9, 2022

Note that the discussion in https://contributors.scala-lang.org/t/make-fewerbraces-available-outside-snapshot-releases/5024/23?u=sjrd was about a previous proposal which did not use : in front of lambda parameters.

@odersky
Copy link
Contributor Author

odersky commented Jul 9, 2022

@gabro For multiple block parameters I would propose what I proposed in this comment on the long contributors thread:

https://contributors.scala-lang.org/t/make-fewerbraces-available-outside-snapshot-releases/5024/167?u=odersky

I'll update the draft with that content.

=> Int)
```

### Other concerns
Copy link
Contributor

Choose a reason for hiding this comment

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

I would like to add here a comment that I wrote there: the proximity with type ascriptions makes code harder to read.

trait X:
  type Y
  def Y: Y

def f(n: Int): (x: X) => x.Y
f(42): ((x: X) => x.Y) // This is not a lambda but a type ascription

Even without involving dependent function types, the proximity between brace-less lambdas and function types is quite close:

// lambda
xs.map: x =>
  x + 1

// type ascription
xs.f: (Int => Int)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

=> is already heavily overloaded in Scala syntax. In practice, a simple way to visually distinguish a lambda argument from a type ascription will be that the lambda argument ends with a => at the end of the line. Yes, you can fool the logic by putting parentheses around it, as in:

  val y = xs.map: ((x: Int) =>
    Int)

But I think this will be done very rarely, and we can suggest it should be avoided. (I.e. if you write a multi-line function type, put the =>s in front rather at the end of lines.) So then the problem that remains is that if you intentionally write confusing layout and you read only superficially then things can be confusing. But that's really nothing out of the ordinary.

`<colon> <indent>` and end with `<outdent>`.
Analogous rules apply for enum bodies, type refinements, and local packages containing nested definitions.

Generally, the possible indentation regions coincide with those regions where braces `{...}` are also legal, no matter whether the braces enclose an expression or a set of definitions. There is so far one exception, though: Arguments to functions can be enclosed in braces but they cannot be simply indented instead. Making indentation always significant for function arguments would be too restrictive and fragile.
Copy link
Contributor

@julienrf julienrf Jul 13, 2022

Choose a reason for hiding this comment

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

Do you mind elaborating on the drawbacks of the status quo? Why is this an important problem?

Also, the brace-less syntax can be used with function arguments:

xs.map(x =>
  val y = x - 1
  y * y
)

This was not possible in Scala 2.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but that does not work in all cases, which is why I would recommend to stick to braces. E.g.

times(10)(
  val x = ...
  x * x
)

does not work.

@odersky
Copy link
Contributor Author

odersky commented Jul 21, 2022

@gabro @julienrf I worked in your suggestions in the proposal.

@chrisandrews-ms
Copy link

Sorry, I'm rather late to the party. I've read through the contributors thread, and it seems to me that all of the reasonable queries have been dealt with in the revised proposal. I'm on the fence about braceless syntax in general, but this proposal seems to be an important enhancement without significant drawbacks, so I'm in favor.

@gabro
Copy link

gabro commented Aug 11, 2022

I agree, and I recommend accepting this proposal at the next SIP meeting.

@dragos
Copy link

dragos commented Aug 14, 2022

I echo @gabro's review. This looks like a good addition to the current indentation-based syntax and I don't see any drawbacks.

@chrisandrews-ms
Copy link

The outcome of the vote at the 26 August SIP Committee meeting was to accept the proposal as an experimental feature. In fact it is already an experimental feature (which predates the current process), but the vote has formalized that status.

Some concerns were raised about ugly syntactic edge cases but it was pointed out that braces and parentheses remain available even when this feature is enabled.

It was also highlighted that colons are in fact not used by control keywords, e.g.

if x < 0 then -x else x

while x >= 0 do x = f(x)

for x <- xs if x > 0
yield x * x

So this proposal still doesn't allow methods with by-name parameters to be invoked in a way that looks exactly like control syntax, but that wasn't considered a blocker for this proposal.

@benhutchison
Copy link

Just wanted to report back with some positive feedback and appreciation ❤️ for this feature, based on a couple of months now of writing Scala 3.3.x in braceless style. I'm really enjoying it 😁! My brain quickly adapted as indentation was already the key cue for block structure. For me, Scala has got unambiguously better by leaving the braces behind.

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

Successfully merging this pull request may close these issues.

7 participants