This topic seems to be the best one about feedback for fewerBraces
, so I’m posting here.
For the sake of evaluating the implicit proposal behind that flag, I have experimented with it in one of my personal projects. As a stylistic exercise, I have tried to remove every single brace in my 8 kLoC codebase. I did manage to do so, although I am clearly not sure whether the price was worth it. Also, as part of my experiment, I made a point of not moving things around in val
s, or replacing braces by parens (unless I absolutely had to, see below).
I made a series of changes by category, gathered in a series of commits. The codebase as a whole is private, so I won’t share it. But you will find the diffs of each commit in the following gist:
Without further ado, here is my feedback, as a commentary on each of those commits. I am not discussing the readability of the resulting code in that list. I leave that as a more subjective discussion towards the end of this post.
1. Use fewerBraces in places where it works as intented out-of-the-box
In the first commit, I applied fewerBraces
to all the places in my codebase where it was clearly the intended use case of the feature, and where it did not require me to do any other change (including formatting changes). In a sense, this is where things went well.
2. Reformat call chains to admit more uses of fewerBraces down the line
This commit is somewhat unrelated to fewerBraces
. It is purely a reformatting of places where my call chain coding style prevented to use fewerBraces
. So I reformatted those call chains to make them amenable to the fewerBraces
changes down the line.
It’s worth observing that these changes introduced more lines, and more indentation levels. This is a problem I already had when adapting my coding style from the general brace-based syntax of Scala 2 to the indentation-based syntax of Scala 3.
3. Use fewerBraces where it works after the previous reformatting
This is like the commit 1., with new spots enabled by the reformatting of commit 2.
4. Where I had to avoid using an _
as lambda param name
This commit exhibits two instances of a bug involving _
. I filed it here:
5. Where I had to use a colon because of a partial function argument
This commit shows a bunch of places where I pass an anonymous partial function as argument. In those cases, I had to use a :
, although I think we could get away without that. I filed that as a feature request here:
6. Where the placement of commas goes very wrong
This commit shows several places where leveraging fewerBraces
leads to argument-separating commas to be displaced to very misleading places. The typical shape is like this before:
foo(
xs.map { x =>
x * x
},
otherArgument
)
which becomes
foo(
xs.map x =>
x * x, // <-- misleading comma here
otherArgument
)
This can also happen with trailing commas.
This is not something I have observed with any other language feature before, including the general indentation syntax of Scala 3. I must say that I find it quite concerning.
7. Where I was forced to use new parens because of curried params
This commit shows the only place where I could not avoid introducing new parens to compensate for the braces. This happens because the lambda argument is followed by another parameter list.
This can be quite common because of methods like groupMapReduce
, which takes 3 different functions as arguments.
(There exists another way, which involves putting a :
alone on a line, but I found that way too horrible to even consider.)
8. Where it goes very wrong because the lambda is an argument of an infix method
Finally, the last commit shows some places where a lambda is an argument to an infix method—a common idiom in Laminar, for example. I have filed another feature request to make this better:
My subjective opinion on the resulting readability
Disclaimer: I was very much against the introduction of the indentation-based syntax in Scala 3. I still think it was a mistake. Not because of the resulting syntax (I use it in that codebase, and it’s fine) but because the change of syntax would inevitably introduce more variability in Scala code styles.
For fewerBraces
, I’m not so much against the change. TBH, I think we went so much over the line with the general indentation syntax that a few more changes with fewerBraces
won’t make a difference.
Subjectively though, I find the resulting code simply harder to read. While it may be an artifact of my experimental methodology, I strongly feel that fewerBraces
is there to get rid of braces for the sake of getting rid of braces—and not to actually improve the developer experience or the readability of the code.
Compare for example
val perCompanyOrNeutral: Set[AssetType] = Company.AllCompaniesAndNeutral
.flatMap { company =>
companyDamAssetNames(company)
.map { (level, assetName) =>
AssetType.Image(assetName, AssetPath(s"assets/dam$level-${company.stringID}.png"))
}.toSet
}.toSet
with
val perCompanyOrNeutral: Set[AssetType] = Company.AllCompaniesAndNeutral
.flatMap company =>
companyDamAssetNames(company)
.map (level, assetName) =>
AssetType.Image(assetName, AssetPath(s"assets/dam$level-${company.stringID}.png"))
.toSet
.toSet
The braces in the first snippet give some visual structure, and help associate the various method calls that belong together. In the second snippet, I have to make quite a bit of extra effort to associate the method calls where they belong.
A counter-argument would be that I should put the result of the other flatMap
in a separate val
first, then call .toSet
on that. I don’t accept that argument, though, as it makes the structure worse, and essentially forces me to write even more code, with less structure, to recover the readability loss of fewerBraces
.
The misleading commas are also very problematic to me in terms of readability. It becomes quite a lot harder to make a mental structure of the code at a glance when those commas are misplaced.
I also don’t like that this syntax effectively makes multi-function methods like groupMapReduce
second-class citizens of the language. There is no good alternative for those. It’s really the language changes telling you that you should never even have been using such methods! And that despite the fact that they are in the standard library.
Summary
As a summary, I would say that I am not at all convinced by this feature. I will repeat my main impression of the feature here: to me, it feels that fewerBraces
is there to get rid of braces for the sake of getting rid of braces—and not to actually improve the developer experience or the readability of the code.