This thread is for feedback of what seems to be Scala 3’s most controversial feature: optional braces.
History
I first seriously considered optional braces about 18 months ago after having played with the idea for several years. At that time it was experimental; we wanted to have something that we could try out on people. The immediate setting for the experiment was the standard 2nd year course on functional programming at EPFL. During that course and after, we experimented with several versions of the syntax. We got the feedback from students, but more important for me was the feedback from my own work: Do the slides and tutorial texts look natural and as simple as possible? Is it easy to explain? Are there hidden traps? Does it have a clean specification and implementation?
In the Spring 2020 the rules were solidified, and we continued to get feedback from users. I also used it now in all of my own work. All my commits from late 2019 onwards use indentation syntax. By that time we had refined the system so that indentation and braces could be freely mixed. Consequently, the name of the feature changed from “indentation syntax” to “optional braces”. Mixing old code and indented code felt surprisingly natural. We had first expected that there would be a clash but that has not turned out to be the case in our experience. Mixing both styles had two other advantages: No global rewrite was necessary, so we could keep the git history clean. And, we got a simple unobtrusive marker whether code was new or old.
My personal experience working with optional braces was overwhelmingly positive. I encountered none of the shortcomings and problems that were predicted. And that holds over a very large range of usage scenarios: from a single tutorial slide to multi-thousand line pull requests. I can say confidently that using optional braces is the single most important productivity boost for me when switching to Scala-3. Of course, this is subjective, not everyone will feel the same. Programming styles are a matter of personal
taste and preference. But I nevertheless like to believe that when I experience a huge advantage in a way of doing things, there will be others that appreciate it as well, and this was born out by informal feedback I got. I explained this view, and the expectation that Scala 3 will have optional braces, in multiple conferences starting with ScalaSphere 2019.
I was so convinced that optional braces are the way forward that I re-recorded my two MOOCs with the new syntax. That amounted to about 20 hours of material overall. This was a large investment of my time (about 3 months overall) and even more time from several others helping me with the editing. If we had stuck with braces, we could probably have kept a large part of the old material, saving us a lot of time.
Technical Design
The rules for optional braces are described here.
To get a feeling what the code looks like, you could take a look at the Scala 3 compiler. In many places old and new are mixed, but some parts were written exclusively with indentation syntax.
Variants
Optional braces for control constructs were quite uncontroversial and did not change much.
We had several design iterations for optional braces in classes. We started with :
as the marker for an indentation block, then tried (1) nothing at all, i.e. every indentation after a class signature opens a block
(2) where
, (3) with
. Every trial went through a complete cycle where the spec and implementation was changed, course material was changed, and we tried it out in teaching and in our own work. After extensive experimentation we decided that :
was the best choice, after all. So we stuck with that.
We also had many discussions about avoiding braces around function arguments. The original design used again :
. Many alternatives were proposed and debated. In the end we decided that it would be premature to settle on a solution now. A revised scheme that allows to drop braces after :
is available under a command-line setting -Yindent-colons. We expect that this will be resolved at some point past 3.0, once the community has gained more experience with the existing rules. We need to debate what the best solution is here, but I’d prefer to keep that out of this thread.
By contrast, we never considered to drop braces altogether. Optional braces will stay optional, just like semicolons are still optional in Scala after 15 years. This means if you don’t like any of this, you have the option to just always write braces where Scala-2 would demand them, and this can be enforced with a linter or the compiler’s -noindent setting.
Possible Objections
If you are against indentation syntax because you had bad experiences with Yaml or Python, you might still come to like the way it’s done in Scala 3. In fact, we have solved many of the problematic aspects of indentation syntax by careful design. For instance:
- Spaces vs tabs: solved by a new interpretation of indentation widths. Spaces and tabs can be mixed, and at the same time the system still does not require an encoding of what a tab is.
- An accidental space can change meaning: solved by careful rules that mean a single missing or additional space can never change the meaning of a program as well as a type system that catches in practice the great majority of multi-space errors. In fact I believe the system is more robust against accidental changes in meaning than what we had in Scala 2.
- It’s hard to find what scope gets closed when a line closes multiple indentation levels: Solved by optional end markers.
- It’s problematic to mix different styles: this was not observed in practice. Scala 2 already has optional braces in that braces are optional around single expressions. Some people write them, others don’t. The new scheme is mostly just more of the same.
Feedback Sought
It would be good to get feedback about concrete aspects of the proposal. How can it be improved? What problems did people encounter? Are there possible fixes that avoid the problems? We are particularly interested in reports based on actual experiences working with the current version of dotty/Scala 3.
Process
I know that optional braces ended up being handled differently than other new Scala-3 features. The discussion about them was always very controversial. It was the one change where I was relying on my authority as informal BDFL to push it through by convincing enough others to go along. So if things turn out badly, I’ll be the one to blame. But I am quite hopeful they won’t.
I also apologize for having sought feedback so late in the game. We dropped the ball on this one. It was because due to Covid all SIP activity was dormant since March 11th. We should have opened this thread over the summer, but nobody thought of it then.