Make "fewerBraces" available outside snapshot releases

I’m someone that really likes the indentation syntax in general, I think it’s wonderful to write in, and the option to add an end marker makes it for me pretty much a strict upgrade to brace syntax

Now that I understand better the proposal that is fewerBraces, I am somewhat strongly against it, I’ll expain those feelings in the following, by splitting two cases with different needs: Regular Scala, and DSLs

Regular Scala

I feel like this change actually makes the language harder to read and learn, for example:

// A
xs.foldLeft(0){ (x,y) =>
  ...
}
// becomes: B
xs.foldLeft(0) (x,y) => // for me, this reads as "(  xs.foldLeft(0) (x,y)  ) =>"
  ...
// but: C
xs.foldLeft(0){ (x,y) => ... }
// doesn't become: D
xs.foldLeft(0) (x,y) => ...
// as this is illegal

The difference between B and D is not at all obvious, it only somewhat makes sense when you remember the following is valid:

// E
xs.foldLeft(0)( (x,y) => ... )

On top of that, it breaks the normally valid “if it fits in one line, you can remove the linefeed” rule, that I take as a given
( “if it fits in one line, you can remove the linefeed, but you might have to add parens” doesn’t feels as good)

As a scala student, the thing that made me fall in love with the language is that there is always a simple and elegant rule beneath everything:

  • 1 + 2 is actually 1.+(2) so you can override it like any other method
  • {} just means "multi line ()" (at least in the context of lambdas)
  • “if it fits in one line, you can remove the linefeed” as discussed above

And then there’s fewerBraces: Sometimes indented suffices, sometimes you need :, sometimes you need parens instead

It’s not clean, it’s not scala !

DSLs

However, indentation syntax needs to be accessible from DSLs !
Therefore, we need a way for users to use indented sections as parameter blocs, hence:

My humble proposal:

An indented bloc starting with : is syntactic sugar for a regular {} bloc:

// P1
xs.map: x =>
  ...
// becomes:
xs.map{ x =>
  ...
}
// P2 The case where the indentation bloc is of width zero is also accepted:
xs.map: x => ...
foo()
// becomes:
xs.map{ x => ... }
foo()

Examples:

// E0  disallowed 
xs.foldLeft(0) (x,y) => 
  ...

// E1  allowed, discouraged ? -> R1
xs.foldLeft(0): (x,y) => ... 

// E2  allowed, discouraged ? -> R1
xs.foldLeft(0): (x,y) => 
  ...

// E3  allowed, even more discouraged ? -> R1
xs.foldLeft(0): 
  (x,y) => ...

// E4  allowed, discouraged ? -> R1
credentials ++ :
   val file = Path.userHome / ".credentials"
   if file.exists
   then Seq(Credentials(file))
   else Seq()

// E5 allowed and encouraged !
def slides = document("Scala 3 goodies"):
  frame("Goals"):
    itemize:
      p("Showcase cool new stuff in Scala 3")
      p("Help you get started with Scala")
      p("Illustrated by Scala 3 DSL (for these slides...)")
      p("https://github.com/bjornregnell/new-in-Scala3")

// E6 allowed
extension (thing: String):
  def f = 2
  def g = "Hello"
// desugars to:
extension (thing: String){
  def f = 2
  def g = "Hello"
}

// E7 still allowed, of course 
// (I would be in favor of deprecating it in favor of E6, but that is for another day)
extension (thing: String)
  def f = 2
  def g = "Hello"

Potential Restrictions:

  1. :-blocs are discouraged outside of DSLs, as brace syntax is good enough for regular scala
  2. restrict where :-blocs are allowed, for example:
    2.1. not after another :-bloc, to avoid groupMapReduce issues mentioned above
    2.2. not after a {}-bloc, to avoid }:
    2.3. your suggestion here
    2.4. this seems easy to detect → potential for helpful errors
  3. potentially a different character than :, for example |
    3.1. : can create problems/confusion as it is also used for types, but already used with this meaning
    3.2. I see this as somewhat secondary to the proposal, comment on the rest first and foremost

Conclusion

For me, scala is a language of powerful, simple ideas

In my opinion, most of the negative view of fewerBraces (and potentially indented syntax as a whole) is a lack of regularity, which fails to make it simple

As is, I am not in support of fewerBraces, I think however with some changes it could be a very clean and powerful feature, and I provided a draft of what that could look like.

P.S: I tried to give names for everything, to simplify speaking about specific things, for example, if you want to talk about the fact that :-blocs are not allowed after a {}-bloc, you can simply refer to R2.2

4 Likes