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:
-
:
-blocs are discouraged outside of DSLs, as brace syntax is good enough for regular scala
- 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
- 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